mirror of
https://github.com/oliverbooth/X10D
synced 2024-11-22 19:58:49 +00:00
commit
7ff391a52e
@ -211,3 +211,4 @@ dotnet_diagnostic.SA1633.severity = silent
|
|||||||
# https://github.com/JosefPihrt/Roslynator/blob/master/docs/analyzers/RCS1090.md
|
# https://github.com/JosefPihrt/Roslynator/blob/master/docs/analyzers/RCS1090.md
|
||||||
dotnet_diagnostic.CA2007.severity = silent
|
dotnet_diagnostic.CA2007.severity = silent
|
||||||
dotnet_diagnostic.RCS1090.severity = silent
|
dotnet_diagnostic.RCS1090.severity = silent
|
||||||
|
dotnet_diagnostic.CA1805.severity = none
|
||||||
|
2
.github/workflows/docfx.yml
vendored
2
.github/workflows/docfx.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Publish Documentation
|
name: Publish Documentation
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
- uses: nikeee/docfx-action@v1.0.0
|
- uses: nikeee/docfx-action@v1.0.0
|
||||||
name: Build Documentation
|
name: Build Documentation
|
||||||
with:
|
with:
|
||||||
|
17
.github/workflows/dotnet.yml
vendored
17
.github/workflows/dotnet.yml
vendored
@ -16,9 +16,12 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: |
|
||||||
|
3.1.x
|
||||||
|
6.0.x
|
||||||
|
7.0.x
|
||||||
|
|
||||||
- name: Add NuGet source
|
- name: Add NuGet source
|
||||||
run: dotnet nuget add source --username oliverbooth --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/oliverbooth/index.json"
|
run: dotnet nuget add source --username oliverbooth --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/oliverbooth/index.json"
|
||||||
@ -29,5 +32,11 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build --no-restore --configuration Release
|
run: dotnet build --no-restore --configuration Release
|
||||||
|
|
||||||
- name: Test
|
- name: Test .NET Core 3.1
|
||||||
run: dotnet test --no-build --verbosity normal --configuration Release
|
run: dotnet test --no-build --verbosity normal --configuration Release --framework netcoreapp3.1
|
||||||
|
|
||||||
|
- name: Test .NET 6
|
||||||
|
run: dotnet test --no-build --verbosity normal --configuration Release --framework net6.0
|
||||||
|
|
||||||
|
- name: Test .NET 7
|
||||||
|
run: dotnet test --no-build --verbosity normal --configuration Release --framework net7.0
|
||||||
|
55
.github/workflows/nightly.yml
vendored
55
.github/workflows/nightly.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: 7.0.x
|
||||||
|
|
||||||
@ -26,16 +26,63 @@ jobs:
|
|||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build -c Debug
|
run: dotnet build --configuration Debug --no-restore -p:VersionSuffix='nightly' -p:BuildNumber=${{ github.run_number }}
|
||||||
|
|
||||||
- name: Build NuGet package
|
- name: Build NuGet package
|
||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
dotnet pack X10D -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='nightly' -p:BuildNumber=${{ github.run_number }}
|
dotnet pack X10D --configuration Debug --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='nightly' -p:BuildNumber=${{ github.run_number }}
|
||||||
dotnet pack X10D.Unity -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='nightly' -p:BuildNumber=${{ github.run_number }}
|
dotnet pack X10D.DSharpPlus --configuration Debug --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='nightly' -p:BuildNumber=${{ github.run_number }}
|
||||||
|
dotnet pack X10D.Hosting --configuration Debug --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='nightly' -p:BuildNumber=${{ github.run_number }}
|
||||||
|
dotnet pack X10D.Unity --configuration Debug --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='nightly' -p:BuildNumber=${{ github.run_number }}
|
||||||
|
|
||||||
- name: Push NuGet Package to GitHub
|
- name: Push NuGet Package to GitHub
|
||||||
run: dotnet nuget push "build/*" --source "github" --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate
|
run: dotnet nuget push "build/*" --source "github" --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate
|
||||||
|
|
||||||
- name: Push NuGet Package to nuget.org
|
- name: Push NuGet Package to nuget.org
|
||||||
run: dotnet nuget push "build/*" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
|
run: dotnet nuget push "build/*" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: build
|
||||||
|
path: build/
|
||||||
|
|
||||||
|
- name: Checkout upm branch
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: upm
|
||||||
|
path: upm
|
||||||
|
|
||||||
|
- name: Build package.json
|
||||||
|
run: |
|
||||||
|
dotnet run --project ./X10D.UpmPackageGenerator/X10D.UpmPackageGenerator.csproj "./X10D/bin/Debug/netstandard2.1/X10D.dll"
|
||||||
|
cp package.json upm/package.json
|
||||||
|
|
||||||
|
- name: Copy built artifacts to upm
|
||||||
|
run: |
|
||||||
|
cd upm
|
||||||
|
cp ../X10D/bin/Debug/netstandard2.1/X10D.dll ./X10D.dll
|
||||||
|
cp ../X10D/bin/Debug/netstandard2.1/X10D.xml ./X10D.xml
|
||||||
|
cp ../X10D.Unity/bin/Debug/netstandard2.1/X10D.Unity.dll ./X10D.Unity.dll
|
||||||
|
cp ../X10D.Unity/bin/Debug/netstandard2.1/X10D.Unity.xml ./X10D.Unity.xml
|
||||||
|
|
||||||
|
- name: Check for changes
|
||||||
|
run: |
|
||||||
|
cd upm
|
||||||
|
git diff --quiet
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Commit update
|
||||||
|
if: ${{ success() }}
|
||||||
|
run: |
|
||||||
|
cd upm
|
||||||
|
git config user.name github-actions
|
||||||
|
git config user.email github-actions@github.com
|
||||||
|
git add X10D.dll
|
||||||
|
git add X10D.Unity.dll
|
||||||
|
git add X10D.xml
|
||||||
|
git add X10D.Unity.xml
|
||||||
|
git add package.json
|
||||||
|
git commit -m "Update upm branch ($GITHUB_SHA)"
|
||||||
|
git push
|
||||||
|
55
.github/workflows/prerelease.yml
vendored
55
.github/workflows/prerelease.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: 7.0.x
|
||||||
|
|
||||||
@ -26,13 +26,15 @@ jobs:
|
|||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build -c Release
|
run: dotnet build --configuration Release --no-restore -p:VersionSuffix='prerelease' -p:BuildNumber=${{ github.run_number }}
|
||||||
|
|
||||||
- name: Build NuGet package
|
- name: Build NuGet package
|
||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
dotnet pack X10D -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='prerelease' -p:BuildNumber=${{ github.run_number }}
|
dotnet pack X10D --configuration Release --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='prerelease' -p:BuildNumber=${{ github.run_number }}
|
||||||
dotnet pack X10D.Unity -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='prerelease' -p:BuildNumber=${{ github.run_number }}
|
dotnet pack X10D.DSharpPlus --configuration Release --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='prerelease' -p:BuildNumber=${{ github.run_number }}
|
||||||
|
dotnet pack X10D.Hosting --configuration Release --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='prerelease' -p:BuildNumber=${{ github.run_number }}
|
||||||
|
dotnet pack X10D.Unity --configuration Release --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build -p:VersionSuffix='prerelease' -p:BuildNumber=${{ github.run_number }}
|
||||||
|
|
||||||
- name: Push NuGet Package to GitHub
|
- name: Push NuGet Package to GitHub
|
||||||
run: dotnet nuget push "build/*" --source "github" --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate
|
run: dotnet nuget push "build/*" --source "github" --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate
|
||||||
@ -40,8 +42,53 @@ jobs:
|
|||||||
- name: Push NuGet Package to nuget.org
|
- name: Push NuGet Package to nuget.org
|
||||||
run: dotnet nuget push "build/*" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
|
run: dotnet nuget push "build/*" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: build
|
||||||
|
path: build/
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: "marvinpinto/action-automatic-releases@latest"
|
uses: "marvinpinto/action-automatic-releases@latest"
|
||||||
with:
|
with:
|
||||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|
||||||
|
- name: Checkout upm branch
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: upm
|
||||||
|
path: upm
|
||||||
|
|
||||||
|
- name: Build package.json
|
||||||
|
run: |
|
||||||
|
dotnet run --project ./X10D.UpmPackageGenerator/X10D.UpmPackageGenerator.csproj "./X10D/bin/Release/netstandard2.1/X10D.dll"
|
||||||
|
cp package.json upm/package.json
|
||||||
|
|
||||||
|
- name: Copy built artifacts to upm
|
||||||
|
run: |
|
||||||
|
cd upm
|
||||||
|
cp ../X10D/bin/Release/netstandard2.1/X10D.dll ./X10D.dll
|
||||||
|
cp ../X10D/bin/Release/netstandard2.1/X10D.xml ./X10D.xml
|
||||||
|
cp ../X10D.Unity/bin/Release/netstandard2.1/X10D.Unity.dll ./X10D.Unity.dll
|
||||||
|
cp ../X10D.Unity/bin/Release/netstandard2.1/X10D.Unity.xml ./X10D.Unity.xml
|
||||||
|
|
||||||
|
- name: Check for changes
|
||||||
|
run: |
|
||||||
|
cd upm
|
||||||
|
git diff --quiet
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Commit update
|
||||||
|
if: ${{ success() }}
|
||||||
|
run: |
|
||||||
|
cd upm
|
||||||
|
git config user.name github-actions
|
||||||
|
git config user.email github-actions@github.com
|
||||||
|
git add X10D.dll
|
||||||
|
git add X10D.Unity.dll
|
||||||
|
git add X10D.xml
|
||||||
|
git add X10D.Unity.xml
|
||||||
|
git add package.json
|
||||||
|
git commit -m "Update upm branch ($GITHUB_SHA)"
|
||||||
|
git push
|
||||||
|
55
.github/workflows/release.yml
vendored
55
.github/workflows/release.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: 7.0.x
|
||||||
|
|
||||||
@ -26,13 +26,15 @@ jobs:
|
|||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build -c Release
|
run: dotnet build --configuration Release --no-restore
|
||||||
|
|
||||||
- name: Build NuGet package
|
- name: Build NuGet package
|
||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
dotnet pack X10D -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build
|
dotnet pack X10D --configuration Release --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build
|
||||||
dotnet pack X10D.Unity -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build
|
dotnet pack X10D.DSharpPlus --configuration Release --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build
|
||||||
|
dotnet pack X10D.Hosting --configuration Release --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build
|
||||||
|
dotnet pack X10D.Unity --configuration Release --no-build -p:SymbolPackageFormat=snupkg --include-symbols --include-source -o build
|
||||||
|
|
||||||
- name: Push NuGet Package to GitHub
|
- name: Push NuGet Package to GitHub
|
||||||
run: dotnet nuget push "build/*" --source "github" --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate
|
run: dotnet nuget push "build/*" --source "github" --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate
|
||||||
@ -40,8 +42,53 @@ jobs:
|
|||||||
- name: Push NuGet Package to nuget.org
|
- name: Push NuGet Package to nuget.org
|
||||||
run: dotnet nuget push "build/*" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
|
run: dotnet nuget push "build/*" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: build
|
||||||
|
path: build/
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: "marvinpinto/action-automatic-releases@latest"
|
uses: "marvinpinto/action-automatic-releases@latest"
|
||||||
with:
|
with:
|
||||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
|
||||||
|
- name: Checkout upm branch
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: upm
|
||||||
|
path: upm
|
||||||
|
|
||||||
|
- name: Build package.json
|
||||||
|
run: |
|
||||||
|
dotnet run --project ./X10D.UpmPackageGenerator/X10D.UpmPackageGenerator.csproj "./X10D/bin/Release/netstandard2.1/X10D.dll"
|
||||||
|
cp package.json upm/package.json
|
||||||
|
|
||||||
|
- name: Copy built artifacts to upm
|
||||||
|
run: |
|
||||||
|
cd upm
|
||||||
|
cp ../X10D/bin/Release/netstandard2.1/X10D.dll ./X10D.dll
|
||||||
|
cp ../X10D/bin/Release/netstandard2.1/X10D.xml ./X10D.xml
|
||||||
|
cp ../X10D.Unity/bin/Release/netstandard2.1/X10D.Unity.dll ./X10D.Unity.dll
|
||||||
|
cp ../X10D.Unity/bin/Release/netstandard2.1/X10D.Unity.xml ./X10D.Unity.xml
|
||||||
|
|
||||||
|
- name: Check for changes
|
||||||
|
run: |
|
||||||
|
cd upm
|
||||||
|
git diff --quiet
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Commit update
|
||||||
|
if: ${{ success() }}
|
||||||
|
run: |
|
||||||
|
cd upm
|
||||||
|
git config user.name github-actions
|
||||||
|
git config user.email github-actions@github.com
|
||||||
|
git add X10D.dll
|
||||||
|
git add X10D.Unity.dll
|
||||||
|
git add X10D.xml
|
||||||
|
git add X10D.Unity.xml
|
||||||
|
git add package.json
|
||||||
|
git commit -m "Update upm branch ($GITHUB_SHA)"
|
||||||
|
git push
|
||||||
|
2
.github/workflows/sonarcloud.yml
vendored
2
.github/workflows/sonarcloud.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 1.11
|
java-version: 1.11
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||||
- name: Cache SonarCloud packages
|
- name: Cache SonarCloud packages
|
||||||
|
2
.github/workflows/source_validator.yml
vendored
2
.github/workflows/source_validator.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: 7.0.x
|
||||||
|
|
||||||
|
4
.github/workflows/unity.yml
vendored
4
.github/workflows/unity.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: 7.0.x
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ jobs:
|
|||||||
cp -r ./X10D.Unity/bin/Release/netstandard2.1/X10D.Unity.dll ./X10D.Unity.Tests/Assets/Libraries/X10D.Unity.dll
|
cp -r ./X10D.Unity/bin/Release/netstandard2.1/X10D.Unity.dll ./X10D.Unity.Tests/Assets/Libraries/X10D.Unity.dll
|
||||||
|
|
||||||
- name: Unity - Test runner
|
- name: Unity - Test runner
|
||||||
uses: game-ci/unity-test-runner@v2.0.2
|
uses: game-ci/unity-test-runner@v2.1.0
|
||||||
env:
|
env:
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
754
CHANGELOG.md
754
CHANGELOG.md
@ -1,205 +1,392 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [3.1.0]
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 3.2.0 - [Unreleased]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Added new library X10D.DSharpPlus.
|
||||||
|
- Added new library X10D.Hosting.
|
||||||
|
- Added .NET 7 target.
|
||||||
|
- X10D: Added `IntrinsicExtensions` and `IntrinsicUtility` which offer methods for vectors in `System.Runtime.Instrinsics`. (#70)
|
||||||
|
- X10D: Added `MathUtility.Bias(float, float)` and `MathUtility.Bias(double, double)`.
|
||||||
|
- X10D: Added `MathUtility.ExponentialDecay(float, float, float)` and `MathUtility.ExponentialDecay(double, double, double)`.
|
||||||
|
- X10D: Added `MathUtility.InverseLerp(float, float, float)` and `MathUtility.InverseLerp(double, double, double)`.
|
||||||
|
- X10D: Added `MathUtility.Pulse(float, float, float)` and `MathUtility.Pulse(double, double, double)`.
|
||||||
|
- X10D: Added `MathUtility.Sawtooth(float)` and `MathUtility.Sawtooth(double)`.
|
||||||
|
- X10D: Added `MathUtility.ScaleRange(float, float, float, float, float)`
|
||||||
|
and `MathUtility.ScaleRange(double, double, double, double, double)`
|
||||||
|
- X10D: Added `MathUtility.Sigmoid(float)` and `MathUtility.Sigmoid(double)`.
|
||||||
|
- X10D: Added `MathUtility.SmoothStep(float, float, float)` and `MathUtility.SmoothStep(double, double, double)`.
|
||||||
|
- X10D: Added `Circle`, `CircleF`, `Cuboid`, `Ellipse`, `EllipseF`, `Line3D`, `Line`, `LineF`, `Polygon`, `PolygonF`, `Polyhedron`,
|
||||||
|
and `Sphere`, to complement System.Drawing structs such as `Point` and `Rectangle`.
|
||||||
|
- X10D: Added `Color.Deconstruct()` - with optional alpha parameter.
|
||||||
|
- X10D: Added `Color.GetClosestConsoleColor()`.
|
||||||
|
- X10D: Added `DateTime.GetIso8601WeekOfYear()` and `DateTimeOffset.GetIso8601WeekOfYear()`.
|
||||||
|
- X10D: Added `DirectoryInfo.Clear()`.
|
||||||
|
- X10D: Added `double.LinearToGamma([gamma])` and `float.LinearToGamma([gamma])`. (#60)
|
||||||
|
- X10D: Added `double.GammaToLinear([gamma])` and `float.GammaToLinear([gamma])`. (#60)
|
||||||
|
- X10D: Added `GreatestCommonFactor` for built-in integer types.
|
||||||
|
- X10D: Added `IEnumerable<T>.ConcatOne(T)`.
|
||||||
|
- X10D: Added `IEnumerable<T>.CountWhereNot(Func<T, bool>)`.
|
||||||
|
- X10D: Added `IEnumerable<T>.FirstWhereNot(Func<T, bool>)`.
|
||||||
|
- X10D: Added `IEnumerable<T>.FirstWhereNotOrDefault(Func<T, bool>)`.
|
||||||
|
- X10D: Added `IEnumerable<T>.LastWhereNot(Func<T, bool>)`.
|
||||||
|
- X10D: Added `IEnumerable<T>.LastWhereNotOrDefault(Func<T, bool>)`.
|
||||||
|
- X10D: Added `IEnumerable<T>.MinMax()` and `IEnumerable<T>.MinMaxBy()`. (#72)
|
||||||
|
- X10D: Added `IEnumerable<T>.WhereNot(Func<T, bool>)`.
|
||||||
|
- X10D: Added `IEnumerable<T>.WhereNotNull()`.
|
||||||
|
- X10D: Added `IEnumerable<string>.Grep(string[, bool])`.
|
||||||
|
- X10D: Added `IList<T>.RemoveRange(Range)`.
|
||||||
|
- X10D: Added `IList<T>.Swap(IList<T>)`. (#62)
|
||||||
|
- X10D: Added `IReadOnlyList<T>.IndexOf(T[, int[, int]])`.
|
||||||
|
- X10D: Added `IReadOnlyList<T>.Slice(int[, int]])`.
|
||||||
|
- X10D: Added `LowestCommonMultiple` for built-in integer types.
|
||||||
|
- X10D: Added `Wrap(T[, T])` for built-in numeric types. (#60)
|
||||||
|
- X10D: Added `Nullable<T>.TryGetValue(out T)`. (#61)
|
||||||
|
- X10D: Added `Point.IsOnLine(LineF)`, `Point.IsOnLine(PointF, PointF)`, and `Point.IsOnLine(Vector2, Vector2)`.
|
||||||
|
- X10D: Added `PointF.IsOnLine(LineF)`, `PointF.IsOnLine(PointF, PointF)`, and `PointF.IsOnLine(Vector2, Vector2)`.
|
||||||
|
- X10D: Added `Point.ToSize()`.
|
||||||
|
- X10D: Added `Point.ToSizeF()`.
|
||||||
|
- X10D: Added `Point.ToVector2()`.
|
||||||
|
- X10D: Added `PointF.Round([float])`.
|
||||||
|
- X10D: Added `PointF.ToSizeF()`.
|
||||||
|
- X10D: Added `PointF.ToVector2()` for .NET < 6.
|
||||||
|
- X10D: Added `PopCount()` for built-in integer types.
|
||||||
|
- X10D: Added `Quaternion.ToAxisAngle(out float, out float)`.
|
||||||
|
- X10D: Added `Quaternion.ToVector3()`.
|
||||||
|
- X10D: Added `Random.NextFrom(Span<T>)` and `Random.NextFrom(ReadOnlySpan<T>)`.
|
||||||
|
- X10D: Added `ReadOnlySpan<char>.CountSubstring(char)`.
|
||||||
|
- X10D: Added `ReadOnlySpan<char>.CountSubstring(ReadOnlySpan<char>[, StringComparison])`.
|
||||||
|
- X10D: Added `ReadOnlySpan<char>.ToTimeSpan()`.
|
||||||
|
- X10D: Added `ReadOnlySpan<T>.Split(T)`.
|
||||||
|
- X10D: Added `ReadOnlySpan<T>.Split(ReadOnlySpan<T>)`.
|
||||||
|
- X10D: Added `RoundUpToPowerOf2()` for built-in integer types.
|
||||||
|
- X10D: Added `Saturate()` for built-in floating-point types.
|
||||||
|
- X10D: Added `Size.ToPoint()`.
|
||||||
|
- X10D: Added `Size.ToPointF()`.
|
||||||
|
- X10D: Added `Size.ToVector2()`.
|
||||||
|
- X10D: Added `Span<char>.CountSubstring(char)`.
|
||||||
|
- X10D: Added `Span<char>.CountSubstring(Span<char>[, StringComparison])`.
|
||||||
|
- X10D: Added `Span<T>.Split(T)`.
|
||||||
|
- X10D: Added `Span<T>.Split(Span<T>)`.
|
||||||
|
- X10D: Added `string.CountSubstring(char)`.
|
||||||
|
- X10D: Added `string.CountSubstring(string[, StringComparison])`.
|
||||||
|
- X10D: Added `string.EnsureStartsWith()` and `string.EnsureEndsWith()`.
|
||||||
|
- X10D: Added `string.IsEmpty()`.
|
||||||
|
- X10D: Added `string.IsWhiteSpace()`.
|
||||||
|
- X10D: Added `string.IsNullOrEmpty()`.
|
||||||
|
- X10D: Added `string.IsNullOrWhiteSpace()`.
|
||||||
|
- X10D: Added `TextReader.EnumerateLines()` and `TextReader.EnumerateLinesAsync()`.
|
||||||
|
- X10D: Added `TimeSpan.TryParse(ReadOnlySpan<char>, out TimeSpan)`.
|
||||||
|
- X10D: Added `Quaternion.Multiply(Vector3)` - this functions as an equivalent to Unity's `Quaternion * Vector3` operator.
|
||||||
|
- X10D: Added `Vector2.Deconstruct()`.
|
||||||
|
- X10D: Added `Vector2.IsOnLine(LineF)`, `Vector2.IsOnLine(PointF, PointF)`, and `Vector2.IsOnLine(Vector2, Vector2)`.
|
||||||
|
- X10D: Added `Vector2.Round([float])`.
|
||||||
|
- X10D: Added `Vector2.ToPointF()`.
|
||||||
|
- X10D: Added `Vector2.ToSizeF()`.
|
||||||
|
- X10D: Added `Vector3.Deconstruct()`.
|
||||||
|
- X10D: Added `Vector3.Round([float])`.
|
||||||
|
- X10D: Added `Vector4.Deconstruct()`.
|
||||||
|
- X10D: Added `Vector4.Round([float])`.
|
||||||
|
- X10D: `ComplexSqrt` is now exposed for all frameworks.
|
||||||
|
- X10D.Unity: Added `DebugUtility`, which mimics `UnityEngine.Debug` while offering more useful primitive drawing methods.
|
||||||
|
- X10D.Unity: Added `System.Drawing.Color.ToUnityColor()`.
|
||||||
|
- X10D.Unity: Added `System.Drawing.Color.ToUnityColor32()`.
|
||||||
|
- X10D.Unity: Added `Color.Deconstruct()` - with optional alpha parameter.
|
||||||
|
- X10D.Unity: Added `Color.GetClosestConsoleColor()`.
|
||||||
|
- X10D.Unity: Added `Color.ToSystemDrawingColor()`.
|
||||||
|
- X10D.Unity: Added `Color32.Deconstruct()` - with optional alpha parameter.
|
||||||
|
- X10D.Unity: Added `Color32.GetClosestConsoleColor()`.
|
||||||
|
- X10D.Unity: Added `Color32.ToSystemDrawingColor()`.
|
||||||
|
- X10D.Unity: Added `Point.ToUnityVector2()`.
|
||||||
|
- X10D.Unity: Added `Point.ToUnityVector2Int()`.
|
||||||
|
- X10D.Unity: Added `PointF.ToUnityVector2()`.
|
||||||
|
- X10D.Unity: Added `Rect.ToSystemRectangleF()`.
|
||||||
|
- X10D.Unity: Added `RectInt.ToSystemRectangle()`.
|
||||||
|
- X10D.Unity: Added `RectInt.ToSystemRectangleF()`.
|
||||||
|
- X10D.Unity: Added `Rectangle.ToUnityRect()`.
|
||||||
|
- X10D.Unity: Added `Rectangle.ToUnityRectInt()`.
|
||||||
|
- X10D.Unity: Added `RectangleF.ToUnityRect()`.
|
||||||
|
- X10D.Unity: Added `Size.ToUnityVector2()`.
|
||||||
|
- X10D.Unity: Added `Size.ToUnityVector2Int()`.
|
||||||
|
- X10D.Unity: Added `SizeF.ToUnityVector2()`.
|
||||||
|
- X10D.Unity: Added `Vector2.Deconstruct()`.
|
||||||
|
- X10D.Unity: Added `Vector2.IsOnLine(LineF)`, `Vector2.IsOnLine(PointF, PointF)`, and `Vector2.IsOnLine(Vector2, Vector2)`.
|
||||||
|
- X10D.Unity: Added `Vector2Int.IsOnLine(LineF)`, `Vector2Int.IsOnLine(PointF, PointF)`, `Vector2Int.IsOnLine(Vector2, Vector2)`,
|
||||||
|
and `Vector2Int.IsOnLine(Vector2Int, Vector2Int)`.
|
||||||
|
- X10D.Unity: Added `Vector2.Round([float])`.
|
||||||
|
- X10D.Unity: Added `Vector2.ToSystemPointF()`.
|
||||||
|
- X10D.Unity: Added `Vector2.ToSystemSizeF()`.
|
||||||
|
- X10D.Unity: Added `Vector2Int.Deconstruct()`.
|
||||||
|
- X10D.Unity: Added `Vector2Int.ToSystemPoint()`.
|
||||||
|
- X10D.Unity: Added `Vector2Int.ToSystemSize()`.
|
||||||
|
- X10D.Unity: Added `Vector2Int.ToSystemVector()`.
|
||||||
|
- X10D.Unity: Added `Vector2Int.WithX()`.
|
||||||
|
- X10D.Unity: Added `Vector2Int.WithY()`.
|
||||||
|
- X10D.Unity: Added `Vector3.Deconstruct()`.
|
||||||
|
- X10D.Unity: Added `Vector3.Round([float])`.
|
||||||
|
- X10D.Unity: Added `Vector3Int.Deconstruct()`.
|
||||||
|
- X10D.Unity: Added `Vector3Int.ToSystemVector()`.
|
||||||
|
- X10D.Unity: Added `Vector3Int.WithX()`.
|
||||||
|
- X10D.Unity: Added `Vector3Int.WithY()`.
|
||||||
|
- X10D.Unity: Added `Vector3Int.WithZ()`.
|
||||||
|
- X10D.Unity: Added `Vector4.Deconstruct()`.
|
||||||
|
- X10D.Unity: Added `Vector4.Round([float])`
|
||||||
|
- X10D.Unity: Added `WaitForFrames` yield instruction.
|
||||||
|
- X10D.Unity: Added `WaitForKeyDown` yield instruction.
|
||||||
|
- X10D.Unity: Added `WaitForKeyUp` yield instruction.
|
||||||
|
- X10D.Unity: Added `WaitForSecondsNoAlloc` yield instruction.
|
||||||
|
- X10D.Unity: Added `WaitForSecondsRealtimeNoAlloc` yield instruction.
|
||||||
|
- X10D.Unity: Added `WaitForTimeSpanNoAlloc` yield instruction.
|
||||||
|
- X10D.Unity: Added `WaitForTimeSpanRealtimeNoAlloc` yield instruction.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- X10D: `T[].Clear` will now correctly clear the specified range of elements by
|
||||||
|
using the [GetOffsetAndLength](https://learn.microsoft.com/en-us/dotnet/api/system.range.getoffsetandlength?view=net-7.0)
|
||||||
|
method.
|
||||||
|
- X10D: `Stream.ReadSingle(Endianness)` now returns a float instead of a double.
|
||||||
|
- X10D: Fixed `Stream.ReadDouble(Endianness)`, `Stream.ReadSingle(Endianness)`, `Stream.WriteDouble(double, Endianness)`,
|
||||||
|
`Stream.WriteSingle(float, Endianness)` writing and reading the wrong endianness.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- X10D: Performance for integer `Unpack` has been dramatically improved using vector parallelization. (#70)
|
||||||
|
- X10D: Performance for `MemberInfo.HasCustomAttribute` has been improved. (#70)
|
||||||
|
- X10D: Performance for `Rune.Repeat` has been improved. (#70)
|
||||||
|
- X10D: `TimeSpanParser.TryParse` now accepts a nullable string, and returns false if this input is null or empty.
|
||||||
|
- X10D.Unity: `Singleton<T>` now caches instance where possible.
|
||||||
|
- X10D.Unity: Conversions between equivalent structures in `System.Numerics` and `UnityEngine` now make use of "unsafe"
|
||||||
|
reinterpretation, rather than constructing new instances. (#70)
|
||||||
|
|
||||||
|
## [3.1.0] - 2022-05-13
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
- Reintroduced Unity support
|
- Reintroduced Unity support
|
||||||
- X10D: Added `Color.Inverted()` (#54)
|
- X10D: Added `Color.Inverted()`. (#54)
|
||||||
- X10D: Added `Color.WithA()` (#55)
|
- X10D: Added `Color.WithA()`. (#55)
|
||||||
- X10D: Added `Color.WithB()` (#55)
|
- X10D: Added `Color.WithB()`. (#55)
|
||||||
- X10D: Added `Color.WithG()` (#55)
|
- X10D: Added `Color.WithG()`. (#55)
|
||||||
- X10D: Added `Color.WithR()` (#55)
|
- X10D: Added `Color.WithR()`. (#55)
|
||||||
- X10D: Added `ICollection<T>.ClearAndDisposeAll()`
|
- X10D: Added `ICollection<T>.ClearAndDisposeAll()`.
|
||||||
- X10D: Added `ICollection<T>.ClearAndDisposeAllAsync()`
|
- X10D: Added `ICollection<T>.ClearAndDisposeAllAsync()`.
|
||||||
- X10D: Added `IEnumerable<T>.For()` (#50)
|
- X10D: Added `IEnumerable<T>.For()`. (#50)
|
||||||
- X10D: Added `IEnumerable<T>.ForEach()` (#50)
|
- X10D: Added `IEnumerable<T>.ForEach()`. (#50)
|
||||||
- X10D: Added `IEnumerable<T>.DisposeAll()`
|
- X10D: Added `IEnumerable<T>.DisposeAll()`.
|
||||||
- X10D: Added `IEnumerable<T>.DisposeAllAsync()`
|
- X10D: Added `IEnumerable<T>.DisposeAllAsync()`.
|
||||||
- X10D: Added `char.IsEmoji`
|
- X10D: Added `char.IsEmoji`.
|
||||||
- X10D: Added `ReadOnlySpan<T>.Count(Predicate<T>)`
|
- X10D: Added `ReadOnlySpan<T>.Count(Predicate<T>)`.
|
||||||
- X10D: Added `Rune.IsEmoji`
|
- X10D: Added `Rune.IsEmoji`.
|
||||||
- X10D: Added `Span<T>.Count(Predicate<T>)`
|
- X10D: Added `Span<T>.Count(Predicate<T>)`.
|
||||||
- X10D: Added `string.IsEmoji`
|
- X10D: Added `string.IsEmoji`.
|
||||||
- X10D: Added `Vector2.WithX()` (#56)
|
- X10D: Added `Vector2.WithX()`. (#56)
|
||||||
- X10D: Added `Vector2.WithY()` (#56)
|
- X10D: Added `Vector2.WithY()`. (#56)
|
||||||
- X10D: Added `Vector3.WithX()` (#56)
|
- X10D: Added `Vector3.WithX()`. (#56)
|
||||||
- X10D: Added `Vector3.WithY()` (#56)
|
- X10D: Added `Vector3.WithY()`. (#56)
|
||||||
- X10D: Added `Vector3.WithZ()` (#56)
|
- X10D: Added `Vector3.WithZ()`. (#56)
|
||||||
- X10D: Added `Vector4.WithX()` (#56)
|
- X10D: Added `Vector4.WithX()`. (#56)
|
||||||
- X10D: Added `Vector4.WithY()` (#56)
|
- X10D: Added `Vector4.WithY()`. (#56)
|
||||||
- X10D: Added `Vector4.WithZ()` (#56)
|
- X10D: Added `Vector4.WithZ()`. (#56)
|
||||||
- X10D: Added `Vector4.WithW()` (#56)
|
- X10D: Added `Vector4.WithW()`. (#56)
|
||||||
- X10D.Unity: Added `Singleton<T>` class
|
- X10D.Unity: Added `Singleton<T>` class.
|
||||||
- X10D.Unity: Added `Color.Inverted()` (#54)
|
- X10D.Unity: Added `Color.Inverted()`. (#54)
|
||||||
- X10D.Unity: Added `Color.WithA()` (#55)
|
- X10D.Unity: Added `Color.WithA()`. (#55)
|
||||||
- X10D.Unity: Added `Color.WithB()` (#55)
|
- X10D.Unity: Added `Color.WithB()`. (#55)
|
||||||
- X10D.Unity: Added `Color.WithG()` (#55)
|
- X10D.Unity: Added `Color.WithG()`. (#55)
|
||||||
- X10D.Unity: Added `Color.WithR()` (#55)
|
- X10D.Unity: Added `Color.WithR()`. (#55)
|
||||||
- X10D.Unity: Added `Color32.Inverted()` (#54)
|
- X10D.Unity: Added `Color32.Inverted()`. (#54)
|
||||||
- X10D.Unity: Added `Color32.WithA()` (#55)
|
- X10D.Unity: Added `Color32.WithA()`. (#55)
|
||||||
- X10D.Unity: Added `Color32.WithB()` (#55)
|
- X10D.Unity: Added `Color32.WithB()`. (#55)
|
||||||
- X10D.Unity: Added `Color32.WithG()` (#55)
|
- X10D.Unity: Added `Color32.WithG()`. (#55)
|
||||||
- X10D.Unity: Added `Color32.WithR()` (#55)
|
- X10D.Unity: Added `Color32.WithR()`. (#55)
|
||||||
- X10D.Unity: Added `Component.GetComponentsInChildrenOnly<T>()`
|
- X10D.Unity: Added `Component.GetComponentsInChildrenOnly<T>()`.
|
||||||
- X10D.Unity: Added `GameObject.GetComponentsInChildrenOnly<T>()`
|
- X10D.Unity: Added `GameObject.GetComponentsInChildrenOnly<T>()`.
|
||||||
- X10D.Unity: Added `GameObject.LookAt(GameObject[, Vector3])`
|
- X10D.Unity: Added `GameObject.LookAt(GameObject[, Vector3])`.
|
||||||
- X10D.Unity: Added `GameObject.LookAt(Transform[, Vector3])`
|
- X10D.Unity: Added `GameObject.LookAt(Transform[, Vector3])`.
|
||||||
- X10D.Unity: Added `GameObject.LookAt(Vector3[, Vector3])`
|
- X10D.Unity: Added `GameObject.LookAt(Vector3[, Vector3])`.
|
||||||
- X10D.Unity: Added `GameObject.SetLayerRecursively(int)` (#57)
|
- X10D.Unity: Added `GameObject.SetLayerRecursively(int)`. (#57)
|
||||||
- X10D.Unity: Added `GameObject.SetParent(GameObject[, bool])`
|
- X10D.Unity: Added `GameObject.SetParent(GameObject[, bool])`.
|
||||||
- X10D.Unity: Added `GameObject.SetParent(Transform[, bool])`
|
- X10D.Unity: Added `GameObject.SetParent(Transform[, bool])`.
|
||||||
- X10D.Unity: Added `System.Numerics.Quaternion.ToUnityQuaternion()`
|
- X10D.Unity: Added `System.Numerics.Quaternion.ToUnityQuaternion()`.
|
||||||
- X10D.Unity: Added `Quaternion.ToSystemQuaternion()`
|
- X10D.Unity: Added `Quaternion.ToSystemQuaternion()`.
|
||||||
- X10D.Unity: Added `Random.NextColorArgb()`
|
- X10D.Unity: Added `Random.NextColorArgb()`.
|
||||||
- X10D.Unity: Added `Random.NextColor32Argb()`
|
- X10D.Unity: Added `Random.NextColor32Argb()`.
|
||||||
- X10D.Unity: Added `Random.NextColorRgb()`
|
- X10D.Unity: Added `Random.NextColorRgb()`.
|
||||||
- X10D.Unity: Added `Random.NextColor32Rgb()`
|
- X10D.Unity: Added `Random.NextColor32Rgb()`.
|
||||||
- X10D.Unity: Added `Random.NextRotation()`
|
- X10D.Unity: Added `Random.NextRotation()`.
|
||||||
- X10D.Unity: Added `Random.NextRotationUniform()`
|
- X10D.Unity: Added `Random.NextRotationUniform()`.
|
||||||
- X10D.Unity: Added `Random.NextUnitVector2()`
|
- X10D.Unity: Added `Random.NextUnitVector2()`.
|
||||||
- X10D.Unity: Added `Random.NextUnitVector3()`
|
- X10D.Unity: Added `Random.NextUnitVector3()`.
|
||||||
- X10D.Unity: Added `Transform.LookAt(GameObject[, Vector3])`
|
- X10D.Unity: Added `Transform.LookAt(GameObject[, Vector3])`.
|
||||||
- X10D.Unity: Added `Transform.SetParent(GameObject[, bool])`
|
- X10D.Unity: Added `Transform.SetParent(GameObject[, bool])`.
|
||||||
- X10D.Unity: Added `System.Numerics.Vector2.ToUnityVector()`
|
- X10D.Unity: Added `System.Numerics.Vector2.ToUnityVector()`.
|
||||||
- X10D.Unity: Added `System.Numerics.Vector3.ToUnityVector()`
|
- X10D.Unity: Added `System.Numerics.Vector3.ToUnityVector()`.
|
||||||
- X10D.Unity: Added `System.Numerics.Vector4.ToUnityVector()`
|
- X10D.Unity: Added `System.Numerics.Vector4.ToUnityVector()`.
|
||||||
- X10D.Unity: Added `Vector2.ToSystemVector()`
|
- X10D.Unity: Added `Vector2.ToSystemVector()`.
|
||||||
- X10D.Unity: Added `Vector3.ToSystemVector()`
|
- X10D.Unity: Added `Vector3.ToSystemVector()`.
|
||||||
- X10D.Unity: Added `Vector4.ToSystemVector()`
|
- X10D.Unity: Added `Vector4.ToSystemVector()`.
|
||||||
- X10D.Unity: Added `Vector2.WithX()` (#56)
|
- X10D.Unity: Added `Vector2.WithX()`. (#56)
|
||||||
- X10D.Unity: Added `Vector2.WithY()` (#56)
|
- X10D.Unity: Added `Vector2.WithY()`. (#56)
|
||||||
- X10D.Unity: Added `Vector3.WithX()` (#56)
|
- X10D.Unity: Added `Vector3.WithX()`. (#56)
|
||||||
- X10D.Unity: Added `Vector3.WithY()` (#56)
|
- X10D.Unity: Added `Vector3.WithY()`. (#56)
|
||||||
- X10D.Unity: Added `Vector3.WithZ()` (#56)
|
- X10D.Unity: Added `Vector3.WithZ()`. (#56)
|
||||||
- X10D.Unity: Added `Vector4.WithX()` (#56)
|
- X10D.Unity: Added `Vector4.WithX()`. (#56)
|
||||||
- X10D.Unity: Added `Vector4.WithY()` (#56)
|
- X10D.Unity: Added `Vector4.WithY()`. (#56)
|
||||||
- X10D.Unity: Added `Vector4.WithZ()` (#56)
|
- X10D.Unity: Added `Vector4.WithZ()`. (#56)
|
||||||
- X10D.Unity: Added `Vector4.WithW()` (#56)
|
- X10D.Unity: Added `Vector4.WithW()`. (#56)
|
||||||
|
|
||||||
## [3.0.0]
|
## [3.0.0] - 2022-04-30
|
||||||
|
|
||||||
In the midst of writing these release notes, I may have missed some important changes. If you notice an API change that is not documented here,
|
In the midst of writing these release notes, I may have missed some important changes. If you notice an API change that is not
|
||||||
|
documented here,
|
||||||
please [open an issue](https://github.com/oliverbooth/X10D/issues)!
|
please [open an issue](https://github.com/oliverbooth/X10D/issues)!
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Added `T.AsArrayValue()`
|
|
||||||
- Added `T.AsEnumerableValue()`
|
- Added `T.AsArrayValue()`.
|
||||||
- Added `T.RepeatValue(int)`
|
- Added `T.AsEnumerableValue()`.
|
||||||
- Added `T.ToJson([JsonSerializerOptions])`
|
- Added `T.RepeatValue(int)`.
|
||||||
- Added `string.FromJson([JsonSerializerOptions])`
|
- Added `T.ToJson([JsonSerializerOptions])`.
|
||||||
- Added `T[].AsReadOnly()`
|
- Added `string.FromJson([JsonSerializerOptions])`.
|
||||||
- Added `T[].Clear([Range])` and `T[].Clear(int, int)`
|
- Added `T[].AsReadOnly()`.
|
||||||
- Added `DateTime.IsLeapYear()`
|
- Added `T[].Clear([Range])` and `T[].Clear(int, int)`.
|
||||||
- Added `DateTimeOffset.IsLeapYear()`
|
- Added `DateTime.IsLeapYear()`.
|
||||||
- Added `Endianness` enum
|
- Added `DateTimeOffset.IsLeapYear()`.
|
||||||
- Added `FileInfo.GetHash<T>()`
|
- Added `Endianness` enum.
|
||||||
- Added `FileInfo.TryWriteHash<T>(Span<byte>, out int)`
|
- Added `FileInfo.GetHash<T>()`.
|
||||||
- Added `IComparable<T>.Clamp(T, T)` - this supersedes `Clamp` defined for hard-coded numeric types (#24)
|
- Added `FileInfo.TryWriteHash<T>(Span<byte>, out int)`.
|
||||||
- Added `IComparable<T1>.GreaterThan(T2)` (#22)
|
- Added `IComparable<T>.Clamp(T, T)` - this supersedes `Clamp` defined for hard-coded numeric types. (#24)
|
||||||
- Added `IComparable<T1>.GreaterThanOrEqualTo(T2)` (#22)
|
- Added `IComparable<T1>.GreaterThan(T2)`. (#22)
|
||||||
- Added `IComparable<T1>.LessThan(T2)` (#22)
|
- Added `IComparable<T1>.GreaterThanOrEqualTo(T2)`. (#22)
|
||||||
- Added `IComparable<T1>.LessThanOrEqualTo(T2)` (#22)
|
- Added `IComparable<T1>.LessThan(T2)`. (#22)
|
||||||
- Added `IComparable<T1>.Max(T)` (#23)
|
- Added `IComparable<T1>.LessThanOrEqualTo(T2)`. (#22)
|
||||||
- Added `IComparable<T1>.Min(T)` (#23)
|
- Added `IComparable<T1>.Max(T)`. (#23)
|
||||||
|
- Added `IComparable<T1>.Min(T)`. (#23)
|
||||||
- Added `IDictionary<TKey, TValue>.AddOrUpdate()`
|
- Added `IDictionary<TKey, TValue>.AddOrUpdate()`
|
||||||
- Added `IEnumerable<TSource>.Product()` and `IEnumerable<TSource>.Product<TResult>(Func<TSource>, TResult)` for all built-in numeric types, computing the product of all (optionally transformed) elements
|
- Added `IEnumerable<TSource>.Product()` and `IEnumerable<TSource>.Product<TResult>(Func<TSource>, TResult)` for all built-in
|
||||||
- Added `IList<T>.Fill(T)` and `IList<T>.Fill(T, int, int)`
|
numeric types, computing the product of all (optionally transformed) elements.
|
||||||
- Added `IPAddress.IsIPv4()` and `IPAddress.IsIPv6()`
|
- Added `IList<T>.Fill(T)` and `IList<T>.Fill(T, int, int)`.
|
||||||
- Added `IReadOnlyList<byte>.Pack8Bit()`
|
- Added `IPAddress.IsIPv4()` and `IPAddress.IsIPv6()`.
|
||||||
- Added `IReadOnlyList<byte>.Pack16Bit()`
|
- Added `IReadOnlyList<byte>.Pack8Bit()`.
|
||||||
- Added `IReadOnlyList<byte>.Pack32Bit()`
|
- Added `IReadOnlyList<byte>.Pack16Bit()`.
|
||||||
- Added `IReadOnlyList<byte>.Pack64Bit()`
|
- Added `IReadOnlyList<byte>.Pack32Bit()`.
|
||||||
- Added `MemberInfo.HasCustomAttribute<T>()` and `MemberInfo.HasCustomAttribute(Type)`
|
- Added `IReadOnlyList<byte>.Pack64Bit()`.
|
||||||
- Added `defaultValue` overload for `MemberInfo.SelectFromCustomAttribute<TAttr, TReturn>()`
|
- Added `MemberInfo.HasCustomAttribute<T>()` and `MemberInfo.HasCustomAttribute(Type)`.
|
||||||
- Added `Random.Next<T>()` (returns a random field from a specified enum type)
|
- Added `defaultValue` overload for `MemberInfo.SelectFromCustomAttribute<TAttr, TReturn>()`.
|
||||||
- Added `Random.NextByte([byte[, byte]])`
|
- Added `Random.Next<T>()` (returns a random field from a specified enum type).
|
||||||
- Added `Random.NextColorArgb()`, returning a random color in RGB space, including random alpha
|
- Added `Random.NextByte([byte[, byte]])`.
|
||||||
- Added `Random.NextColorRgb()`, returning a random color in RGB space with alpha 255
|
- Added `Random.NextColorArgb()`, returning a random color in RGB space, including random alpha.
|
||||||
- Added `Random.NextDouble(double[, double])`
|
- Added `Random.NextColorRgb()`, returning a random color in RGB space with alpha 255.
|
||||||
- Added `Random.NextInt16([short[, short]])`
|
- Added `Random.NextDouble(double[, double])`.
|
||||||
- Added `Random.NextSingle(float[, float])` (#34)
|
- Added `Random.NextInt16([short[, short]])`.
|
||||||
- Added `Random.NextUnitVector2()`
|
- Added `Random.NextSingle(float[, float])`. (#34)
|
||||||
- Added `Random.NextUnitVector3()`
|
- Added `Random.NextUnitVector2()`.
|
||||||
- Added `Random.NextRotation()`
|
- Added `Random.NextUnitVector3()`.
|
||||||
- Added `Rune.Repeat(int)`
|
- Added `Random.NextRotation()`.
|
||||||
- Added `byte.IsEven()`
|
- Added `Rune.Repeat(int)`.
|
||||||
- Added `byte.IsOdd()`
|
- Added `byte.IsEven()`.
|
||||||
- Added `byte.IsPrime()`
|
- Added `byte.IsOdd()`.
|
||||||
- Added `byte.UnpackBits()`
|
- Added `byte.IsPrime()`.
|
||||||
- Added `byte.RangeTo(byte)`, `byte.RangeTo(short)`, `byte.RangeTo(int)`, and `byte.RangeTo(long)`
|
- Added `byte.UnpackBits()`.
|
||||||
- Added `int.Mod(int)`
|
- Added `byte.RangeTo(byte)`, `byte.RangeTo(short)`, `byte.RangeTo(int)`, and `byte.RangeTo(long)`.
|
||||||
- Added `int.RangeTo(int)`, and `int.RangeTo(long)`
|
- Added `int.Mod(int)`.
|
||||||
- Added `int.UnpackBits()`
|
- Added `int.RangeTo(int)`, and `int.RangeTo(long)`.
|
||||||
- Added `long.Mod(long)`
|
- Added `int.UnpackBits()`.
|
||||||
- Added `long.RangeTo(long)`
|
- Added `long.Mod(long)`.
|
||||||
- Added `long.UnpackBits()`
|
- Added `long.RangeTo(long)`.
|
||||||
- Added `sbyte.IsEven()`
|
- Added `long.UnpackBits()`.
|
||||||
- Added `sbyte.IsOdd()`
|
- Added `sbyte.IsEven()`.
|
||||||
- Added `sbyte.IsPrime()`
|
- Added `sbyte.IsOdd()`.
|
||||||
- Added `sbyte.Mod(sbyte)`
|
- Added `sbyte.IsPrime()`.
|
||||||
- Added `short.IsEven()`
|
- Added `sbyte.Mod(sbyte)`.
|
||||||
- Added `short.IsOdd()`
|
- Added `short.IsEven()`.
|
||||||
- Added `short.Mod(short)`
|
- Added `short.IsOdd()`.
|
||||||
- Added `short.RangeTo(short)`, `short.RangeTo(int)`, and `short.RangeTo(long)`
|
- Added `short.Mod(short)`.
|
||||||
- Added `short.UnpackBits()`
|
- Added `short.RangeTo(short)`, `short.RangeTo(int)`, and `short.RangeTo(long)`.
|
||||||
- Added `string.IsPalindrome()`
|
- Added `short.UnpackBits()`.
|
||||||
- Added `Stream.GetHash<T>()`
|
- Added `string.IsPalindrome()`.
|
||||||
- Added `Stream.TryWriteHash<T>(Span<byte>, out int)`
|
- Added `Stream.GetHash<T>()`.
|
||||||
- Added `Stream.ReadInt16([Endian])`
|
- Added `Stream.TryWriteHash<T>(Span<byte>, out int)`.
|
||||||
- Added `Stream.ReadInt32([Endian])`
|
- Added `Stream.ReadInt16([Endian])`.
|
||||||
- Added `Stream.ReadInt64([Endian])`
|
- Added `Stream.ReadInt32([Endian])`.
|
||||||
- Added `Stream.ReadUInt16([Endian])`
|
- Added `Stream.ReadInt64([Endian])`.
|
||||||
- Added `Stream.ReadUInt32([Endian])`
|
- Added `Stream.ReadUInt16([Endian])`.
|
||||||
- Added `Stream.ReadUInt64([Endian])`
|
- Added `Stream.ReadUInt32([Endian])`.
|
||||||
- Added `Stream.Write(short, [Endian])`
|
- Added `Stream.ReadUInt64([Endian])`.
|
||||||
- Added `Stream.Write(int, [Endian])`
|
- Added `Stream.Write(short, [Endian])`.
|
||||||
- Added `Stream.Write(long, [Endian])`
|
- Added `Stream.Write(int, [Endian])`.
|
||||||
- Added `Stream.Write(ushort, [Endian])`
|
- Added `Stream.Write(long, [Endian])`.
|
||||||
- Added `Stream.Write(uint, [Endian])`
|
- Added `Stream.Write(ushort, [Endian])`.
|
||||||
- Added `Stream.Write(ulong, [Endian])`
|
- Added `Stream.Write(uint, [Endian])`.
|
||||||
- Added `TimeSpan.Ago()`
|
- Added `Stream.Write(ulong, [Endian])`.
|
||||||
- Added `TimeSpan.FromNow()`
|
- Added `TimeSpan.Ago()`.
|
||||||
- Added `TimeSpanParser.TryParse` which supersedes `TimeSpanParser.Parse`
|
- Added `TimeSpan.FromNow()`.
|
||||||
- Added `Sqrt()` and `ComplexSqrt()` for all built-in decimal types
|
- Added `TimeSpanParser.TryParse` which supersedes `TimeSpanParser.Parse`.
|
||||||
- Added `All()` and `Any()` for `Span<T>` and `ReadOnlySpan<T>`, mimicking the corresponding methods in `System.Linq`
|
- Added `Sqrt()` and `ComplexSqrt()` for all built-in decimal types.
|
||||||
- Added `Sign()` for built-in numeric types. For unsigned types, this never returns -1
|
- Added `All()` and `Any()` for `Span<T>` and `ReadOnlySpan<T>`, mimicking the corresponding methods in `System.Linq`.
|
||||||
- Added `Type.Implements<T>()` and `Type.Implements(Type)` (#25)
|
- Added `Sign()` for built-in numeric types. For unsigned types, this never returns -1.
|
||||||
- Added `Type.Inherits<T>()` and `Type.Inherits(Type)` (#25)
|
- Added `Type.Implements<T>()` and `Type.Implements(Type)`. (#25)
|
||||||
- Added `DigitalRoot` function for built-in integer types
|
- Added `Type.Inherits<T>()` and `Type.Inherits(Type)`. (#25)
|
||||||
- Added `Factorial` function for built-in integer types
|
- Added `DigitalRoot` function for built-in integer types.
|
||||||
- Added `HostToNetworkOrder` and `NetworkToHostOrder` for `short`, `int`, and `long`
|
- Added `Factorial` function for built-in integer types.
|
||||||
- Added `IsLeapYear` function for `DateTime` and `DateTimeOffset`, as well as built-in numeric types
|
- Added `HostToNetworkOrder` and `NetworkToHostOrder` for `short`, `int`, and `long`.
|
||||||
- Added `MultiplicativePersistence` function for built-in integer types
|
- Added `IsLeapYear` function for `DateTime` and `DateTimeOffset`, as well as built-in numeric types.
|
||||||
- Added `RotateLeft` and `RotateRight` for built-in integer types
|
- Added `MultiplicativePersistence` function for built-in integer types.
|
||||||
- Added trigonometric functions for built-in numeric types, including `Acos()`, `Asin()`, `Atan()`, `Atan2()`, `Cos()`, `Sin()`, `Tan()` (#49)
|
- Added `RotateLeft` and `RotateRight` for built-in integer types.
|
||||||
- Added time-related extension methods for built-in numeric types, including `Milliseconds()`, `Seconds()`, `Minutes()`, `Hours()`, `Days()`, and `Weeks()`. `Ticks()` is also available, but only for integers; not floating point
|
- Added trigonometric functions for built-in numeric types,
|
||||||
- Added `StringBuilderReader` (inheriting `TextReader`) which allows reading from a `StringBuilder` without consuming the underlying string
|
including `Acos()`, `Asin()`, `Atan()`, `Atan2()`, `Cos()`, `Sin()`, `Tan()` (#49)
|
||||||
- Added extension methods for `System.Decimal`
|
- Added time-related extension methods for built-in numeric types,
|
||||||
|
including `Milliseconds()`, `Seconds()`, `Minutes()`, `Hours()`, `Days()`, and `Weeks()`. `Ticks()` is also available, but only
|
||||||
|
for integers; not floating point.
|
||||||
|
- Added `StringBuilderReader` (inheriting `TextReader`) which allows reading from a `StringBuilder` without consuming the
|
||||||
|
underlying string.
|
||||||
|
- Added extension methods for `System.Decimal`.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Updated to .NET 6 (#45)
|
|
||||||
- Methods defined to accept `byte[]` have been changed accept `IReadOnlyList<byte>`
|
- Updated to .NET 6. (#45)
|
||||||
- Extension methods are now defined in appropriate child namespaces to reduce the risk of name collisions (#7)
|
- Methods defined to accept `byte[]` have been changed accept `IReadOnlyList<byte>`.
|
||||||
- `char[].Random(int)`, `char[].Random(int, int)`, `IEnumerable<char>.Random(int)`, and `IEnumerable<char>.Random(int, int)` have been redefined as `Random.NextString(IReadOnlyList<char>, int)`
|
- Extension methods are now defined in appropriate child namespaces to reduce the risk of name collisions. (#7)
|
||||||
- `IComparable<T>.Between(T, T)` has been redefined as `IComparable<T1>.Between(T2, T3, [InclusiveOptions])` to allow comparison of disparate yet comparable types, and also offers inclusivity options
|
- `char[].Random(int)`, `char[].Random(int, int)`, `IEnumerable<char>.Random(int)`, and `IEnumerable<char>.Random(int, int)` have
|
||||||
- `DateTime` extensions now wrap `DateTimeOffset` extensions
|
been redefined as `Random.NextString(IReadOnlyList<char>, int)`.
|
||||||
- `DateTime.ToUnixTimestamp([bool])` has been redefined as `DateTime.ToUnixTimeMilliseconds()` and `DateTime.ToUnixTimeSeconds()`
|
- `IComparable<T>.Between(T, T)` has been redefined as `IComparable<T1>.Between(T2, T3, [InclusiveOptions])` to allow comparison
|
||||||
- `Dictionary<T1, T2>.ToGetParameters()`, `IDictionary<T1, T2>.ToGetParameters()`, and `IReadOnlyDictionary<T1, T2>.ToGetParameters()`, has been redefined as `IEnumerable<KeyValuePair<T1, T2>>.ToGetParameters()`
|
of disparate yet comparable types, and also offers inclusivity options.
|
||||||
- `Dictionary<T1, T2>.ToConnectionString()`, `IDictionary<T1, T2>.ToConnectionString()`, and `IReadOnlyDictionary<T1, T2>.ToConnectionString()`, has been redefined as `IEnumerable<KeyValuePair<T1, T2>>.ToConnectionString()`
|
- `DateTime` extensions now wrap `DateTimeOffset` extensions.
|
||||||
- `IList<T>.OneOf([Random])` and `IEnumerable<T>.OneOf([Random])` have been redefined as `Random.NextFrom<T>(IEnumerable<T>)` to fall in line with the naming convention of `System.Random` (#21)
|
- `DateTime.ToUnixTimestamp([bool])` has been redefined as `DateTime.ToUnixTimeMilliseconds()` and `DateTime.ToUnixTimeSeconds()`.
|
||||||
- `IList<T>.Shuffle([Random])` now uses a Fisher-Yates shuffle implementation
|
- `Dictionary<T1, T2>.ToGetParameters()`, `IDictionary<T1, T2>.ToGetParameters()`,
|
||||||
- `IList<T>.Shuffle([Random])` has been repurposed to shuffle the list in place, rather than returning a new enumerable
|
and `IReadOnlyDictionary<T1, T2>.ToGetParameters()`, has been redefined as `IEnumerable<KeyValuePair<T1, T2>>.ToGetParameters()`.
|
||||||
- `IEnumerable<T>.Shuffle([Random])` has been renamed to `IEnumerable<T>.Shuffled([Random])` to avoid confusion with `IList<T>.Shuffle([Random])`
|
- `Dictionary<T1, T2>.ToConnectionString()`, `IDictionary<T1, T2>.ToConnectionString()`,
|
||||||
- `Random.CoinToss()` has been redefined as `Random.NextBoolean()` to fall in line with the naming convention of `System.Random`
|
and `IReadOnlyDictionary<T1, T2>.ToConnectionString()`, has been redefined
|
||||||
- `Random.OneOf<T>(T[])` and `Random.OneOf<T>(IList<T>)` have been redefined as `Random.NextFrom<T>(IEnumerable<T>)` to fall in line with the naming convention of `System.Random`
|
as `IEnumerable<KeyValuePair<T1, T2>>.ToConnectionString()`.
|
||||||
- `Enum.Next([bool])` and `Enum.Previous([bool])` have been redefined as `Enum.Next()`, `Enum.Previous()`, `Enum.NextUnchecked()`, `Enum.PreviousUnchecked()`. The `Unchecked` variants of these methods do not perform index validation, and will throw `IndexOutOfRangeException` when attempting to access an invalid index. The checked variants will perform a modulo to wrap the index
|
- `IList<T>.OneOf([Random])` and `IEnumerable<T>.OneOf([Random])` have been redefined as `Random.NextFrom<T>(IEnumerable<T>)` to
|
||||||
- Seperated `string.WithAlternative(string, [bool])` to `string.WithEmptyAlternative(string)` and `string.WithWhiteSpaceAlternative(string)`
|
fall in line with the naming convention of `System.Random`. (#21)
|
||||||
- `string.AsNullIfEmpty()` and `string.AsNullIfWhiteSpace()` now accept a nullable `string`
|
- `IList<T>.Shuffle([Random])` now uses a Fisher-Yates shuffle implementation.
|
||||||
|
- `IList<T>.Shuffle([Random])` has been repurposed to shuffle the list in place, rather than returning a new enumerable.
|
||||||
|
- `IEnumerable<T>.Shuffle([Random])` has been renamed to `IEnumerable<T>.Shuffled([Random])` to avoid confusion
|
||||||
|
with `IList<T>.Shuffle([Random])`.
|
||||||
|
- `Random.CoinToss()` has been redefined as `Random.NextBoolean()` to fall in line with the naming convention of `System.Random`.
|
||||||
|
- `Random.OneOf<T>(T[])` and `Random.OneOf<T>(IList<T>)` have been redefined as `Random.NextFrom<T>(IEnumerable<T>)` to fall in
|
||||||
|
line with the naming convention of `System.Random`.
|
||||||
|
- `Enum.Next([bool])` and `Enum.Previous([bool])` have been redefined.
|
||||||
|
as `Enum.Next()`, `Enum.Previous()`, `Enum.NextUnchecked()`, `Enum.PreviousUnchecked()`. The `Unchecked` variants of these
|
||||||
|
methods do not perform index validation, and will throw `IndexOutOfRangeException` when attempting to access an invalid index.
|
||||||
|
The checked variants will perform a modulo to wrap the index.
|
||||||
|
- Seperated `string.WithAlternative(string, [bool])` to `string.WithEmptyAlternative(string)`
|
||||||
|
and `string.WithWhiteSpaceAlternative(string)`.
|
||||||
|
- `string.AsNullIfEmpty()` and `string.AsNullIfWhiteSpace()` now accept a nullable `string`.
|
||||||
- `IEnumerable<byte>.GetString([Encoding])` has been renamed to `IReadOnlyList<byte>.ToString` and its `Encoding` parameter has
|
- `IEnumerable<byte>.GetString([Encoding])` has been renamed to `IReadOnlyList<byte>.ToString` and its `Encoding` parameter has
|
||||||
been made non-optional
|
been made non-optional.
|
||||||
- Fixed a bug where `IEnumerable<KeyValuePair<K,V>>.ToConnectionString()` would not sanitize types with custom `ToString()`
|
- Fixed a bug where `IEnumerable<KeyValuePair<K,V>>.ToConnectionString()` would not sanitize types with custom `ToString()`
|
||||||
implementation (#20)
|
implementation. (#20)
|
||||||
Renamed `string.Random(int[, Random])` to `string.Randomize(int[, Random])`
|
Renamed `string.Random(int[, Random])` to `string.Randomize(int[, Random])`.
|
||||||
- Redefined `char[].Random(int)`, `char[].Random(int, Random)`, `IEnumerable<char>.Random(int)`, and `IEnumerable<char>.Random(int, Random)`, as `Random.NextString(IReadOnlyList<char>, int)`
|
- Redefined `char[].Random(int)`, `char[].Random(int, Random)`, `IEnumerable<char>.Random(int)`,
|
||||||
|
and `IEnumerable<char>.Random(int, Random)`, as `Random.NextString(IReadOnlyList<char>, int)`.
|
||||||
- Improved performance for:
|
- Improved performance for:
|
||||||
- `string.IsLower()`
|
- `string.IsLower()`
|
||||||
- `string.IsUpper()`
|
- `string.IsUpper()`
|
||||||
@ -207,46 +394,52 @@ please [open an issue](https://github.com/oliverbooth/X10D/issues)!
|
|||||||
- `TimeSpanParser`
|
- `TimeSpanParser`
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Indefinitely suspended Unity support, until such a time that Unity can be updated to a newer version of .NET. See: https://forum.unity.com/threads/unity-future-net-development-status.1092205/
|
|
||||||
- Removed `bool.And(bool)`
|
- Indefinitely suspended Unity support, until such a time that Unity can be updated to a newer version of .NET.
|
||||||
- Removed `bool.NAnd(bool)`
|
See: https://forum.unity.com/threads/unity-future-net-development-status.1092205/
|
||||||
- Removed `bool.NOr(bool)`
|
- Removed `bool.And(bool)`.
|
||||||
- Removed `bool.Not(bool)`
|
- Removed `bool.NAnd(bool)`.
|
||||||
- Removed `bool.Or(bool)`
|
- Removed `bool.NOr(bool)`.
|
||||||
- Removed `bool.ToByte()`
|
- Removed `bool.Not(bool)`.
|
||||||
- Removed `bool.ToInt16()`
|
- Removed `bool.Or(bool)`.
|
||||||
- Removed `bool.ToInt64()`
|
- Removed `bool.ToByte()`.
|
||||||
- Removed `bool.XNOr()`
|
- Removed `bool.ToInt16()`.
|
||||||
- Removed `bool.XOr()`
|
- Removed `bool.ToInt64()`.
|
||||||
- Removed `IConvertible.To<T>([IFormatProvider])` (#13)
|
- Removed `bool.XNOr()`.
|
||||||
- Removed `IConvertible.ToOrDefault<T>([IFormatProvider])` (#13)
|
- Removed `bool.XOr()`.
|
||||||
- Removed `IConvertible.ToOrDefault<T>(out T, [IFormatProvider])` (#13)
|
- Removed `IConvertible.To<T>([IFormatProvider])`. (#13)
|
||||||
- Removed `IConvertible.ToOrNull<T>([IFormatProvider])` (#13)
|
- Removed `IConvertible.ToOrDefault<T>([IFormatProvider])`. (#13)
|
||||||
- Removed `IConvertible.ToOrNull<T>(out T, [IFormatProvider])` (#13)
|
- Removed `IConvertible.ToOrDefault<T>(out T, [IFormatProvider])`. (#13)
|
||||||
- Removed `IConvertible.ToOrOther<T>(T, [IFormatProvider])` (#13)
|
- Removed `IConvertible.ToOrNull<T>([IFormatProvider])`. (#13)
|
||||||
- Removed `IConvertible.ToOrOther<T>(out T, T, [IFormatProvider])` (#13)
|
- Removed `IConvertible.ToOrNull<T>(out T, [IFormatProvider])`. (#13)
|
||||||
- Removed `IEnumerable<T>.Split(int)` - this functionality is now provided by .NET in the form of the `Chunk` method. See: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.chunk?view=net-6.0
|
- Removed `IConvertible.ToOrOther<T>(T, [IFormatProvider])`. (#13)
|
||||||
- Removed `MemberInfo.GetDefaultValue()` (use `SelectFromCustomAttribute()` instead)
|
- Removed `IConvertible.ToOrOther<T>(out T, T, [IFormatProvider])`. (#13)
|
||||||
- Removed `MemberInfo.GetDescription()` (use `SelectFromCustomAttribute()` instead)
|
- Removed `IEnumerable<T>.Split(int)` - this functionality is now provided by .NET in the form of the `Chunk` method.
|
||||||
- Removed `int.ToBoolean()`
|
See: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.chunk?view=net-6.0.
|
||||||
- Removed `long.ToBoolean()`
|
- Removed `MemberInfo.GetDefaultValue()` (use `SelectFromCustomAttribute()` instead).
|
||||||
- Removed `short.ToBoolean()`
|
- Removed `MemberInfo.GetDescription()` (use `SelectFromCustomAttribute()` instead).
|
||||||
- Removed `uint.ToBoolean()`
|
- Removed `int.ToBoolean()`.
|
||||||
- Removed `ushort.ToBoolean()`
|
- Removed `long.ToBoolean()`.
|
||||||
- Removed `ulong.ToBoolean()`
|
- Removed `short.ToBoolean()`.
|
||||||
- Removed `WaitHandle.WaitOneAsync()`. For suspensions of execution during asynchronous operations, favour `TaskCompletionSource` or `TaskCompletionSource<T>`. See: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource?view=net-6.0 and https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource-1?view=net-6.0
|
- Removed `uint.ToBoolean()`.
|
||||||
|
- Removed `ushort.ToBoolean()`.
|
||||||
|
- Removed `ulong.ToBoolean()`.
|
||||||
|
- Removed `WaitHandle.WaitOneAsync()`. For suspensions of execution during asynchronous operations, favour `TaskCompletionSource`
|
||||||
|
or `TaskCompletionSource<T>`.
|
||||||
|
See: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource?view=net-6.0
|
||||||
|
and https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource-1?view=net-6.0
|
||||||
|
|
||||||
## [2.6.0] - 2020-10-20
|
## [2.6.0] - 2020-10-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add `string.AsNullIfEmpty()`
|
- Add `string.AsNullIfEmpty()`.
|
||||||
- Returns the current string, or `null` if the current string is null or empty.
|
- Returns the current string, or `null` if the current string is null or empty.
|
||||||
- Add `string.AsNullIfWhiteSpace()`
|
- Add `string.AsNullIfWhiteSpace()`.
|
||||||
- Returns the current string, or `null` if the current string is null, empty, or consists of only whitespace.
|
- Returns the current string, or `null` if the current string is null, empty, or consists of only whitespace.
|
||||||
- Add `string.Reverse()`
|
- Add `string.Reverse()`.
|
||||||
- Reverses the current string
|
- Reverses the current string.
|
||||||
- Add `string.WithAlternative()`
|
- Add `string.WithAlternative()`.
|
||||||
- Returns the current string, or an alternative value if the current string is null or empty, or optionally if the current
|
- Returns the current string, or an alternative value if the current string is null or empty, or optionally if the current
|
||||||
string consists of only whitespace.
|
string consists of only whitespace.
|
||||||
|
|
||||||
@ -262,30 +455,30 @@ please [open an issue](https://github.com/oliverbooth/X10D/issues)!
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- `WaitHandle.WaitOneAsync()`
|
- `WaitHandle.WaitOneAsync()`.
|
||||||
- Wraps `WaitHandle.WaitOne` as a `Task`
|
- Wraps `WaitHandle.WaitOne` as a `Task`.
|
||||||
- Add support for Unity 2019.4.3f1
|
- Add support for Unity 2019.4.3f1.
|
||||||
- Add `GameObject.LookAt(GameObject)`
|
- Add `GameObject.LookAt(GameObject)`.
|
||||||
- Rotates the Transform on the current GameObject so that it faces the Transform on another GameObject
|
- Rotates the Transform on the current GameObject so that it faces the Transform on another GameObject.
|
||||||
- Add `GameObject.LookAt(Transform)`
|
- Add `GameObject.LookAt(Transform)`.
|
||||||
- Rotates the Transform on the current GameObject so that it faces another transform
|
- Rotates the Transform on the current GameObject so that it faces another transform.
|
||||||
- Add `Transform.LookAt(GameObject)`
|
- Add `Transform.LookAt(GameObject)`
|
||||||
- Rotates the current Transform so that it faces the Transform on another GameObject
|
- Rotates the current Transform so that it faces the Transform on another GameObject.
|
||||||
- Add `Vector3.Round([float])`
|
- Add `Vector3.Round([float])`.
|
||||||
- Returns a rounded Vector3 by calling `float.Round()` on each component
|
- Returns a rounded Vector3 by calling `float.Round()` on each component.
|
||||||
- Add `Vector3.WithX(float)`
|
- Add `Vector3.WithX(float)`.
|
||||||
- Returns a Vector3 with a new X component value
|
- Returns a Vector3 with a new X component value.
|
||||||
- Add `Vector3.WithY(float)`
|
- Add `Vector3.WithY(float)`.
|
||||||
- Returns a Vector3 with a new Y component value
|
- Returns a Vector3 with a new Y component value.
|
||||||
- Add `Vector3.WithZ(float)`
|
- Add `Vector3.WithZ(float)`.
|
||||||
- Returns a Vector3 with a new Z component value
|
- Returns a Vector3 with a new Z component value.
|
||||||
- Add `Vector3.WithXY(float, float)`
|
- Add `Vector3.WithXY(float, float)`.
|
||||||
- Returns a Vector3 with new X and Y component values
|
- Returns a Vector3 with new X and Y component values.
|
||||||
- Add `Vector3.WithXZ(float, float)`
|
- Add `Vector3.WithXZ(float, float)`.
|
||||||
- Returns a Vector3 with new X and Z component values
|
- Returns a Vector3 with new X and Z component values.
|
||||||
- Add `Vector3.WithYZ(float, float)`
|
- Add `Vector3.WithYZ(float, float)`.
|
||||||
- Returns a Vector3 with new Y and Z component values
|
- Returns a Vector3 with new Y and Z component values.
|
||||||
- Add `BetterBehavior` (experimental wrapper over `MonoBehaviour`)
|
- Add `BetterBehavior` (experimental wrapper over `MonoBehaviour`).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@ -299,18 +492,18 @@ please [open an issue](https://github.com/oliverbooth/X10D/issues)!
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add `string.ChangeEncoding(Encoding, Encoding)`
|
- Add `string.ChangeEncoding(Encoding, Encoding)`.
|
||||||
- Converts this string from one encoding to another
|
- Converts this string from one encoding to another.
|
||||||
- Add `string.IsLower()`
|
- Add `string.IsLower()`.
|
||||||
- Determines if all alpha characters in this string are considered lowercase
|
- Determines if all alpha characters in this string are considered lowercase.
|
||||||
- Add `string.IsUpper()`
|
- Add `string.IsUpper()`.
|
||||||
- Determines if all alpha characters in this string are considered uppercase
|
- Determines if all alpha characters in this string are considered uppercase.
|
||||||
|
|
||||||
- Various extension methods with regards to reflection:
|
- Various extension methods with regards to reflection:
|
||||||
- `GetDefaultValue` and `GetDefaultValue<T>` - gets the value stored in the member's `DefaultValue` attribute
|
- `GetDefaultValue` and `GetDefaultValue<T>` - gets the value stored in the member's `DefaultValue` attribute.
|
||||||
- `GetDescription`- gets the value stored in the member's `Description` attribute
|
- `GetDescription`- gets the value stored in the member's `Description` attribute.
|
||||||
- `SelectFromCustomAttribute<T1, T2>` - Internally calls `GetCustomAttribute<T1>` and passes it to a `Func<T1, T2>` so that
|
- `SelectFromCustomAttribute<T1, T2>` - Internally calls `GetCustomAttribute<T1>` and passes it to a `Func<T1, T2>` so that
|
||||||
specific members may be selected
|
specific members may be selected.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@ -324,26 +517,26 @@ please [open an issue](https://github.com/oliverbooth/X10D/issues)!
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add `bool bool.And(bool)`
|
- Add `bool bool.And(bool)`.
|
||||||
- Performs logical AND
|
- Performs logical AND.
|
||||||
- Add `bool bool.Or(bool)`
|
- Add `bool bool.Or(bool)`.
|
||||||
- Performs logical OR
|
- Performs logical OR.
|
||||||
- Add `bool bool.Not(bool)`
|
- Add `bool bool.Not(bool)`.
|
||||||
- Performs logical NOT
|
- Performs logical NOT.
|
||||||
- Add `bool bool.XOr(bool)`
|
- Add `bool bool.XOr(bool)`.
|
||||||
- Performs Logical XOR
|
- Performs Logical XOR.
|
||||||
- Add `bool bool.NAnd(bool)`
|
- Add `bool bool.NAnd(bool)`.
|
||||||
- Performs logical NAND
|
- Performs logical NAND.
|
||||||
- Add `bool bool.NOr(bool)`
|
- Add `bool bool.NOr(bool)`.
|
||||||
- Performs logical NOR
|
- Performs logical NOR.
|
||||||
- Add `bool bool.XNOr(bool)`
|
- Add `bool bool.XNOr(bool)`.
|
||||||
- Performs logical XNOR
|
- Performs logical XNOR.
|
||||||
- Add `byte bool.ToByte()`
|
- Add `byte bool.ToByte()`.
|
||||||
- 1 if `true`, 0 otherwise
|
- 1 if `true`, 0 otherwise.
|
||||||
- Add `short bool.ToInt16()`
|
- Add `short bool.ToInt16()`.
|
||||||
- 1 if `true`, 0 otherwise
|
- 1 if `true`, 0 otherwise.
|
||||||
- Add `long bool.ToInt64()`
|
- Add `long bool.ToInt64()`.
|
||||||
- 1 if `true`, 0 otherwise
|
- 1 if `true`, 0 otherwise.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@ -357,23 +550,24 @@ please [open an issue](https://github.com/oliverbooth/X10D/issues)!
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add `IEnumerable<T>.Split(int)`
|
- Add `IEnumerable<T>.Split(int)`.
|
||||||
- Performs the same operation as the previously defined `IEnumerable<byte>.Chunkify(int)`, except now accepts any type `T`
|
- Performs the same operation as the previously defined `IEnumerable<byte>.Chunkify(int)`, except now accepts any type `T`.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Fix `DateTime.Last(DayOfWeek)` implementation
|
- Fix `DateTime.Last(DayOfWeek)` implementation.
|
||||||
- Now returns the correct date/time for a given day of the week
|
- Now returns the correct date/time for a given day of the week.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Remove `IEnumerable<byte>.Chunkify(int)`
|
- Remove `IEnumerable<byte>.Chunkify(int)`.
|
||||||
- Replaced by a method of the same behaviour `IEnumerable<T>.Split(int)`
|
- Replaced by a method of the same behaviour `IEnumerable<T>.Split(int)`.
|
||||||
|
|
||||||
## Earlier versions
|
## Earlier versions
|
||||||
|
|
||||||
### ***Not documented***
|
Earlier versions of this package are undocumented and unlisted from package results.
|
||||||
|
|
||||||
|
[unreleased]: https://github.com/oliverbooth/X10D/compare/v3.1.0...develop
|
||||||
[3.1.0]: https://github.com/oliverbooth/X10D/releases/tag/v3.1.0
|
[3.1.0]: https://github.com/oliverbooth/X10D/releases/tag/v3.1.0
|
||||||
[3.0.0]: https://github.com/oliverbooth/X10D/releases/tag/v3.0.0
|
[3.0.0]: https://github.com/oliverbooth/X10D/releases/tag/v3.0.0
|
||||||
[2.6.0]: https://github.com/oliverbooth/X10D/releases/tag/2.6.0
|
[2.6.0]: https://github.com/oliverbooth/X10D/releases/tag/2.6.0
|
||||||
|
@ -5,7 +5,7 @@ or submit a pull request.
|
|||||||
|
|
||||||
### Pull request guidelines
|
### Pull request guidelines
|
||||||
|
|
||||||
This project uses C# 10.0 language features, and adheres to StyleCop rules with some minor adjustments.
|
This project uses C# 11.0 language features where feasible, and adheres to StyleCop rules with some minor adjustments.
|
||||||
There is an `.editorconfig` included in this repository. For quick and painless pull requests, ensure that the analyzer does not
|
There is an `.editorconfig` included in this repository. For quick and painless pull requests, ensure that the analyzer does not
|
||||||
throw warnings.
|
throw warnings.
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ throw warnings.
|
|||||||
|
|
||||||
Below are a few pointers to which you may refer, but keep in mind this is not an exhaustive list:
|
Below are a few pointers to which you may refer, but keep in mind this is not an exhaustive list:
|
||||||
|
|
||||||
- Use C# 10.0 features where possible
|
- Use C# 11.0 features where possible
|
||||||
- Try to ensure code is CLS-compliant. Where this is not possible, decorate methods with `CLSCompliantAttribute` and pass `false`
|
- Try to ensure code is CLS-compliant. Where this is not possible, decorate methods with `CLSCompliantAttribute` and pass `false`
|
||||||
- Follow all .NET guidelines and coding conventions.
|
- Follow all .NET guidelines and coding conventions.
|
||||||
See https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions
|
See https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions
|
||||||
@ -33,11 +33,11 @@ When in doubt, follow .NET guidelines.
|
|||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
When introducing a new extension method, you must ensure that you have also defined a unit test that asserts its correct behavior.
|
When introducing a new extension method, you must ensure that you have also defined a unit test that asserts its correct behavior.
|
||||||
The code style guidelines and code-analysis rules apply to the `X10D.Tests` equally as much as `X10D`, although documentation may
|
The code style guidelines and code-analysis rules apply to the `X10D.Tests` as much as `X10D`, although documentation may
|
||||||
be briefer. Refer to existing tests as a guideline.
|
be briefer. Refer to existing tests as a guideline.
|
||||||
|
|
||||||
### Disclaimer
|
### Disclaimer
|
||||||
|
|
||||||
In the event of a code style violation, a pull request may left open (or closed entirely) without merging. Keep in mind this does
|
In the event of a code style violation, a pull request may be left open (or closed entirely) without merging. Keep in mind this does
|
||||||
not mean the theory or implementation of the method is inherently bad or rejected entirely (although if this is the case, it will
|
not mean the theory or implementation of the method is inherently bad or rejected entirely (although if this is the case, it will
|
||||||
be outlined)
|
be outlined)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2019-2022 Oliver Booth
|
Copyright (c) 2019-2023 Oliver Booth
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
26
README.md
26
README.md
@ -1,12 +1,12 @@
|
|||||||
<h1 align="center"><img src="https://raw.githubusercontent.com/oliverbooth/X10D/develop/banner.png"></h1>
|
<h1 align="center"><img src="branding_Banner.png"></h1>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/oliverbooth/X10D/actions?query=workflow%3A%22.NET+Core%22"><img src="https://img.shields.io/github/workflow/status/oliverbooth/X10D/.NET%20Core" alt="GitHub Workflow Status" title="GitHub Workflow Status"></a>
|
<a href="https://github.com/oliverbooth/X10D/actions/workflows/dotnet.yml"><img src="https://img.shields.io/github/actions/workflow/status/oliverbooth/X10D/dotnet.yml?style=flat-square" alt="GitHub Workflow Status" title="GitHub Workflow Status"></a>
|
||||||
<a href="https://github.com/oliverbooth/X10D/issues"><img src="https://img.shields.io/github/issues/oliverbooth/X10D" alt="GitHub Issues" title="GitHub Issues"></a>
|
<a href="https://github.com/oliverbooth/X10D/issues"><img src="https://img.shields.io/github/issues/oliverbooth/X10D?style=flat-square" alt="GitHub Issues" title="GitHub Issues"></a>
|
||||||
<a href="https://sonarcloud.io/dashboard?id=oliverbooth_X10D"><img src="https://img.shields.io/sonar/coverage/oliverbooth_X10D?server=https%3A%2F%2Fsonarcloud.io" alt="Coverage"></a>
|
<a href="https://sonarcloud.io/dashboard?id=oliverbooth_X10D"><img src="https://img.shields.io/sonar/coverage/oliverbooth_X10D?server=https%3A%2F%2Fsonarcloud.io&style=flat-square" alt="Coverage"></a>
|
||||||
<a href="https://www.nuget.org/packages/X10D/"><img src="https://img.shields.io/nuget/dt/X10D" alt="NuGet Downloads" title="NuGet Downloads"></a>
|
<a href="https://www.nuget.org/packages/X10D/"><img src="https://img.shields.io/nuget/dt/X10D?style=flat-square" alt="NuGet Downloads" title="NuGet Downloads"></a>
|
||||||
<a href="https://www.nuget.org/packages/X10D/"><img src="https://img.shields.io/nuget/v/X10D?label=stable" alt="Stable Version" title="Stable Version"></a>
|
<a href="https://www.nuget.org/packages/X10D/"><img src="https://img.shields.io/nuget/v/X10D?label=stable&style=flat-square" alt="Stable Version" title="Stable Version"></a>
|
||||||
<a href="https://www.nuget.org/packages/X10D/"><img src="https://img.shields.io/nuget/vpre/X10D?label=nightly" alt="Nightly Version" title="Nightly Version"></a>
|
<a href="https://www.nuget.org/packages/X10D/"><img src="https://img.shields.io/nuget/vpre/X10D?label=nightly&style=flat-square" alt="Nightly Version" title="Nightly Version"></a>
|
||||||
<a href="https://github.com/oliverbooth/X10D/blob/master/LICENSE.md"><img src="https://img.shields.io/github/license/oliverbooth/X10D" alt="MIT License" title="MIT License"></a>
|
<a href="https://github.com/oliverbooth/X10D/blob/master/LICENSE.md"><img src="https://img.shields.io/github/license/oliverbooth/X10D?style=flat-square" alt="MIT License" title="MIT License"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
### About
|
### About
|
||||||
@ -17,18 +17,14 @@ X10D (pronounced *extend*), is a .NET package that provides extension methods fo
|
|||||||
## Installation
|
## Installation
|
||||||
### NuGet installation
|
### NuGet installation
|
||||||
```ps
|
```ps
|
||||||
Install-Package X10D -Version 3.1.0
|
Install-Package X10D -Version 3.2.0
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manual installation
|
### Manual installation
|
||||||
Download the [latest release](https://github.com/oliverbooth/X10D/releases/latest) from this repository and adding a direct assembly reference for your chosen platform.
|
Download the [latest release](https://github.com/oliverbooth/X10D/releases/latest) from this repository and adding a direct assembly reference for your chosen platform.
|
||||||
|
|
||||||
### Unity installation
|
### Unity installation
|
||||||
Starting with Unity 2021.2, support for .NET Standard 2.1 has been added. With this change, I am confident providing support for this version for the time being, with only minimal feature-loss.
|
For the Unity installation guide, refer to the [README.md in X10D.Unity](X10D.Unity/README.md).
|
||||||
To add X10D into your Unity project, goto the [Package Manager window](https://docs.unity3d.com/Manual/upm-ui.html), and choose to install from a Git URL, and use the URL https://github.com/oliverbooth/X10D.git#upm
|
|
||||||
|
|
||||||
Parity with the main branch of X10D, and full .NET 6 feature support, is planned - but a timeline is not yet available. Unity plan to add .NET 6 support in the near future.
|
|
||||||
For more information, see [this forum post](https://forum.unity.com/threads/unity-future-net-development-status.1092205/).
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
I'm planning on writing complete and extensive documentation in the near future. As of this time, feel free to browse the source or the API using your favourite IDE.
|
I'm planning on writing complete and extensive documentation in the near future. As of this time, feel free to browse the source or the API using your favourite IDE.
|
||||||
@ -38,4 +34,4 @@ For those familiar with the 2.6.0 API, please read [CHANGELOG.md](CHANGELOG.md)
|
|||||||
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
X10D is released under the MIT License. See [here](https://github.com/oliverbooth/X10D/blob/master/LICENSE.md) for more details.
|
X10D is released under the MIT License. See [here](https://github.com/oliverbooth/X10D/blob/main/LICENSE.md) for more details.
|
||||||
|
70
X10D.DSharpPlus/X10D.DSharpPlus.csproj
Normal file
70
X10D.DSharpPlus/X10D.DSharpPlus.csproj
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>net7.0;net6.0;netstandard2.1</TargetFrameworks>
|
||||||
|
<LangVersion>11.0</LangVersion>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<ImplicitUsings>true</ImplicitUsings>
|
||||||
|
<Authors>Oliver Booth</Authors>
|
||||||
|
<NeutralLanguage>en</NeutralLanguage>
|
||||||
|
<RepositoryUrl>https://github.com/oliverbooth/X10D</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<Description>Extension methods on crack.</Description>
|
||||||
|
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||||
|
<PackageIcon>branding_Icon.png</PackageIcon>
|
||||||
|
<PackageIconUrl/>
|
||||||
|
<PackageTags>dotnet extension-methods</PackageTags>
|
||||||
|
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/../CHANGELOG.md"))</PackageReleaseNotes>
|
||||||
|
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
|
||||||
|
<VersionPrefix>3.2.0</VersionPrefix>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<ExcludeFromCodeCoverage>true</ExcludeFromCodeCoverage>
|
||||||
|
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
|
||||||
|
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(VersionSuffix)' != '' And '$(BuildNumber)' == ''">
|
||||||
|
<Version>$(VersionPrefix)-$(VersionSuffix)</Version>
|
||||||
|
<AssemblyVersion>$(VersionPrefix).0</AssemblyVersion>
|
||||||
|
<FileVersion>$(VersionPrefix).0</FileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(VersionSuffix)' != '' And '$(BuildNumber)' != ''">
|
||||||
|
<Version>$(VersionPrefix)-$(VersionSuffix).$(BuildNumber)</Version>
|
||||||
|
<AssemblyVersion>$(VersionPrefix).$(BuildNumber)</AssemblyVersion>
|
||||||
|
<FileVersion>$(VersionPrefix).$(BuildNumber)</FileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(VersionSuffix)' == ''">
|
||||||
|
<Version>$(VersionPrefix)</Version>
|
||||||
|
<AssemblyVersion>$(VersionPrefix).0</AssemblyVersion>
|
||||||
|
<FileVersion>$(VersionPrefix).0</FileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DSharpPlus" Version="4.3.0" PrivateAssets="All"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\branding_Icon.png">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath/>
|
||||||
|
</None>
|
||||||
|
<None Include="..\LICENSE.md">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath/>
|
||||||
|
</None>
|
||||||
|
<None Include="..\CHANGELOG.md">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath/>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
1
X10D.DSharpPlus/src/Assembly.cs
Normal file
1
X10D.DSharpPlus/src/Assembly.cs
Normal file
@ -0,0 +1 @@
|
|||||||
|
[assembly: CLSCompliant(false)]
|
80
X10D.DSharpPlus/src/DiscordChannelExtensions.cs
Normal file
80
X10D.DSharpPlus/src/DiscordChannelExtensions.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
using DSharpPlus;
|
||||||
|
using DSharpPlus.Entities;
|
||||||
|
|
||||||
|
namespace X10D.DSharpPlus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="DiscordChannel" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class DiscordChannelExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the category of this channel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel whose category to retrieve.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The category of <paramref name="channel" />, or <paramref name="channel" /> itself if it is already a category;
|
||||||
|
/// <see langword="null" /> if this channel is not defined in a category.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="channel" /> is <see langword="null" />.</exception>
|
||||||
|
public static DiscordChannel? GetCategory(this DiscordChannel channel)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(channel);
|
||||||
|
#else
|
||||||
|
if (channel is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(channel));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (channel.IsCategory)
|
||||||
|
{
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel.Parent is not { } parent)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normalizes a <see cref="DiscordChannel" /> so that the internal client is assured to be a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The <see cref="DiscordChannel" /> to normalize.</param>
|
||||||
|
/// <param name="client">The target client.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="DiscordChannel" /> whose public values will match <paramref name="channel" />, but whose internal client
|
||||||
|
/// is <paramref name="client" />.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// <para><paramref name="channel" /> is <see langword="null" /></para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="client" /> is <see langword="null" /></para>
|
||||||
|
/// </exception>
|
||||||
|
public static async Task<DiscordChannel> NormalizeClientAsync(this DiscordChannel channel, DiscordClient client)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(channel);
|
||||||
|
ArgumentNullException.ThrowIfNull(client);
|
||||||
|
#else
|
||||||
|
if (channel is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(client));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return await client.GetChannelAsync(channel.Id).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
79
X10D.DSharpPlus/src/DiscordClientExtensions.cs
Normal file
79
X10D.DSharpPlus/src/DiscordClientExtensions.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using DSharpPlus;
|
||||||
|
using DSharpPlus.Entities;
|
||||||
|
using DSharpPlus.Exceptions;
|
||||||
|
|
||||||
|
namespace X10D.DSharpPlus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="DiscordClient" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class DiscordClientExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instructs the client to automatically join all existing threads, and any newly-created threads.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="DiscordClient" /> whose events should be subscribed.</param>
|
||||||
|
/// <param name="rejoinIfRemoved">
|
||||||
|
/// <see langword="true" /> to automatically rejoin a thread if this client was removed; otherwise,
|
||||||
|
/// <see langword="false" />.
|
||||||
|
/// </param>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="client" /> is <see langword="null" />.</exception>
|
||||||
|
public static void AutoJoinThreads(this DiscordClient client, bool rejoinIfRemoved = true)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(client);
|
||||||
|
#else
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(client));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
client.GuildAvailable += (_, args) => args.Guild.JoinAllThreadsAsync();
|
||||||
|
client.ThreadCreated += (_, args) => args.Thread.JoinThreadAsync();
|
||||||
|
|
||||||
|
if (rejoinIfRemoved)
|
||||||
|
{
|
||||||
|
client.ThreadMembersUpdated += (_, args) =>
|
||||||
|
{
|
||||||
|
if (args.RemovedMembers.Any(m => m.Id == client.CurrentUser.Id))
|
||||||
|
return args.Thread.JoinThreadAsync();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a user by their ID. If the user is not found, <see langword="null" /> is returned instead of
|
||||||
|
/// <see cref="NotFoundException" /> being thrown.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The Discord client.</param>
|
||||||
|
/// <param name="userId">The ID of the user to retrieve.</param>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="client" /> is <see langword="null" />.</exception>
|
||||||
|
public static async Task<DiscordUser?> GetUserOrNullAsync(this DiscordClient client, ulong userId)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(client);
|
||||||
|
#else
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(client));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// we should never use exceptions for flow control but this is D#+ we're talking about.
|
||||||
|
// NotFoundException isn't even documented, and yet it gets thrown when a user doesn't exist.
|
||||||
|
// so this method should hopefully clearly express that - and at least using exceptions for flow control *here*,
|
||||||
|
// removes the need to do the same in consumer code.
|
||||||
|
// god I hate this.
|
||||||
|
return await client.GetUserAsync(userId).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (NotFoundException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
239
X10D.DSharpPlus/src/DiscordEmbedBuilderExtensions.cs
Normal file
239
X10D.DSharpPlus/src/DiscordEmbedBuilderExtensions.cs
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
using DSharpPlus.Entities;
|
||||||
|
|
||||||
|
namespace X10D.DSharpPlus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="DiscordEmbedBuilder" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class DiscordEmbedBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a field of any value type to the embed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The <see cref="DiscordEmbedBuilder" /> to modify.</param>
|
||||||
|
/// <param name="name">The name of the embed field.</param>
|
||||||
|
/// <param name="value">The value of the embed field.</param>
|
||||||
|
/// <param name="inline"><see langword="true" /> to display this field inline; otherwise, <see langword="false" />.</param>
|
||||||
|
/// <typeparam name="T">The type of <paramref name="value" />.</typeparam>
|
||||||
|
/// <returns>The current instance of <see cref="DiscordEmbedBuilder" />; that is, <paramref name="builder" />.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="builder" /> is <see langword="null" />.</exception>
|
||||||
|
public static DiscordEmbedBuilder AddField<T>(
|
||||||
|
this DiscordEmbedBuilder builder,
|
||||||
|
string name,
|
||||||
|
T? value,
|
||||||
|
bool inline = false)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(builder);
|
||||||
|
#else
|
||||||
|
if (builder is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return builder.AddField(name, value?.ToString(), inline);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Conditionally adds a field to the embed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The <see cref="DiscordEmbedBuilder" /> to modify.</param>
|
||||||
|
/// <param name="condition">The condition whose value is used to determine whether the field will be added.</param>
|
||||||
|
/// <param name="name">The name of the embed field.</param>
|
||||||
|
/// <param name="value">The value of the embed field.</param>
|
||||||
|
/// <param name="inline"><see langword="true" /> to display this field inline; otherwise, <see langword="false" />.</param>
|
||||||
|
/// <typeparam name="T">The type of <paramref name="value" />.</typeparam>
|
||||||
|
/// <returns>The current instance of <see cref="DiscordEmbedBuilder" />; that is, <paramref name="builder" />.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="builder" /> is <see langword="null" />.</exception>
|
||||||
|
public static DiscordEmbedBuilder AddFieldIf<T>(
|
||||||
|
this DiscordEmbedBuilder builder,
|
||||||
|
bool condition,
|
||||||
|
string name,
|
||||||
|
T? value,
|
||||||
|
bool inline = false)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(builder);
|
||||||
|
#else
|
||||||
|
if (builder is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (condition)
|
||||||
|
{
|
||||||
|
builder.AddField(name, value?.ToString(), inline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Conditionally adds a field to the embed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The <see cref="DiscordEmbedBuilder" /> to modify.</param>
|
||||||
|
/// <param name="predicate">The predicate whose return value is used to determine whether the field will be added.</param>
|
||||||
|
/// <param name="name">The name of the embed field.</param>
|
||||||
|
/// <param name="value">The value of the embed field.</param>
|
||||||
|
/// <param name="inline"><see langword="true" /> to display this field inline; otherwise, <see langword="false" />.</param>
|
||||||
|
/// <typeparam name="T">The type of <paramref name="value" />.</typeparam>
|
||||||
|
/// <returns>The current instance of <see cref="DiscordEmbedBuilder" />; that is, <paramref name="builder" />.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// <para><paramref name="builder" /> is <see langword="null" />.</para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="predicate" /> is <see langword="null" />.</para>
|
||||||
|
/// </exception>
|
||||||
|
public static DiscordEmbedBuilder AddFieldIf<T>(
|
||||||
|
this DiscordEmbedBuilder builder,
|
||||||
|
Func<bool> predicate,
|
||||||
|
string name,
|
||||||
|
T? value,
|
||||||
|
bool inline = false)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(builder);
|
||||||
|
ArgumentNullException.ThrowIfNull(predicate);
|
||||||
|
#else
|
||||||
|
if (builder is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predicate is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(predicate));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (predicate.Invoke())
|
||||||
|
{
|
||||||
|
builder.AddField(name, value?.ToString(), inline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Conditionally adds a field to the embed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The <see cref="DiscordEmbedBuilder" /> to modify.</param>
|
||||||
|
/// <param name="predicate">The predicate whose return value is used to determine whether the field will be added.</param>
|
||||||
|
/// <param name="name">The name of the embed field.</param>
|
||||||
|
/// <param name="valueFactory">The delegate whose return value will be used as the value of the embed field.</param>
|
||||||
|
/// <param name="inline"><see langword="true" /> to display this field inline; otherwise, <see langword="false" />.</param>
|
||||||
|
/// <typeparam name="T">The return type of <paramref name="valueFactory" />.</typeparam>
|
||||||
|
/// <returns>The current instance of <see cref="DiscordEmbedBuilder" />; that is, <paramref name="builder" />.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// <para><paramref name="builder" /> is <see langword="null" />.</para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="predicate" /> is <see langword="null" />.</para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="valueFactory" /> is <see langword="null" />.</para>
|
||||||
|
/// </exception>
|
||||||
|
public static DiscordEmbedBuilder AddFieldIf<T>(
|
||||||
|
this DiscordEmbedBuilder builder,
|
||||||
|
Func<bool> predicate,
|
||||||
|
string name,
|
||||||
|
Func<T?> valueFactory,
|
||||||
|
bool inline = false)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(builder);
|
||||||
|
ArgumentNullException.ThrowIfNull(predicate);
|
||||||
|
ArgumentNullException.ThrowIfNull(valueFactory);
|
||||||
|
#else
|
||||||
|
if (builder is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predicate is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(predicate));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueFactory is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(valueFactory));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (predicate.Invoke())
|
||||||
|
{
|
||||||
|
builder.AddField(name, valueFactory.Invoke()?.ToString(), inline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Conditionally adds a field to the embed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The <see cref="DiscordEmbedBuilder" /> to modify.</param>
|
||||||
|
/// <param name="condition">The condition whose value is used to determine whether the field will be added.</param>
|
||||||
|
/// <param name="name">The name of the embed field.</param>
|
||||||
|
/// <param name="valueFactory">The delegate whose return value will be used as the value of the embed field.</param>
|
||||||
|
/// <param name="inline"><see langword="true" /> to display this field inline; otherwise, <see langword="false" />.</param>
|
||||||
|
/// <typeparam name="T">The return type of <paramref name="valueFactory" />.</typeparam>
|
||||||
|
/// <returns>The current instance of <see cref="DiscordEmbedBuilder" />; that is, <paramref name="builder" />.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// <para><paramref name="builder" /> is <see langword="null" />.</para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="valueFactory" /> is <see langword="null" />.</para>
|
||||||
|
/// </exception>
|
||||||
|
public static DiscordEmbedBuilder AddFieldIf<T>(
|
||||||
|
this DiscordEmbedBuilder builder,
|
||||||
|
bool condition,
|
||||||
|
string name,
|
||||||
|
Func<T?> valueFactory,
|
||||||
|
bool inline = false)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(builder);
|
||||||
|
ArgumentNullException.ThrowIfNull(valueFactory);
|
||||||
|
#else
|
||||||
|
if (builder is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
}
|
||||||
|
if (valueFactory is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(valueFactory));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (condition)
|
||||||
|
{
|
||||||
|
builder.AddField(name, valueFactory.Invoke()?.ToString(), inline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the embed's author.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The embed builder to modify.</param>
|
||||||
|
/// <param name="user">The author.</param>
|
||||||
|
/// <returns>The current instance of <see cref="DiscordEmbedBuilder" />.</returns>
|
||||||
|
public static DiscordEmbedBuilder WithAuthor(this DiscordEmbedBuilder builder, DiscordUser user)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(builder);
|
||||||
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
|
#else
|
||||||
|
if (builder is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
}
|
||||||
|
if (user is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return builder.WithAuthor(user.GetUsernameWithDiscriminator(), iconUrl: user.AvatarUrl);
|
||||||
|
}
|
||||||
|
}
|
97
X10D.DSharpPlus/src/DiscordGuildExtensions.cs
Normal file
97
X10D.DSharpPlus/src/DiscordGuildExtensions.cs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
using DSharpPlus;
|
||||||
|
using DSharpPlus.Entities;
|
||||||
|
using DSharpPlus.Exceptions;
|
||||||
|
|
||||||
|
namespace X10D.DSharpPlus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="DiscordGuild" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class DiscordGuildExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Joins all active threads in the guild that this client has permission to view.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guild">The guild whose active threads to join.</param>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="guild" /> is <see langword="null" />.</exception>
|
||||||
|
public static async Task JoinAllThreadsAsync(this DiscordGuild guild)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(guild);
|
||||||
|
#else
|
||||||
|
if (guild is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(guild));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
await Task.WhenAll(guild.Threads.Values.Select(t => t.JoinThreadAsync())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a guild member by their ID. If the member is not found, <see langword="null" /> is returned instead of
|
||||||
|
/// <see cref="NotFoundException" /> being thrown.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guild">The guild whose member list to search.</param>
|
||||||
|
/// <param name="userId">The ID of the member to retrieve.</param>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="guild" /> is <see langword="null" />.</exception>
|
||||||
|
public static async Task<DiscordMember?> GetMemberOrNullAsync(this DiscordGuild guild, ulong userId)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(guild);
|
||||||
|
#else
|
||||||
|
if (guild is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(guild));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// we should never use exceptions for flow control but this is D#+ we're talking about.
|
||||||
|
// NotFoundException isn't even documented, and yet it gets thrown when a member doesn't exist.
|
||||||
|
// so this method should hopefully clearly express that - and at least using exceptions for flow control *here*,
|
||||||
|
// removes the need to do the same in consumer code.
|
||||||
|
// god I hate this.
|
||||||
|
return await guild.GetMemberAsync(userId).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (NotFoundException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normalizes a <see cref="DiscordGuild" /> so that the internal client is assured to be a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guild">The <see cref="DiscordGuild" /> to normalize.</param>
|
||||||
|
/// <param name="client">The target client.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="DiscordGuild" /> whose public values will match <paramref name="guild" />, but whose internal client is
|
||||||
|
/// <paramref name="client" />.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// <para><paramref name="guild" /> is <see langword="null" /></para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="client" /> is <see langword="null" /></para>
|
||||||
|
/// </exception>
|
||||||
|
public static async Task<DiscordGuild> NormalizeClientAsync(this DiscordGuild guild, DiscordClient client)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(guild);
|
||||||
|
ArgumentNullException.ThrowIfNull(client);
|
||||||
|
#else
|
||||||
|
if (guild is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(guild));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(client));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return await client.GetGuildAsync(guild.Id).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
73
X10D.DSharpPlus/src/DiscordMemberExtensions.cs
Normal file
73
X10D.DSharpPlus/src/DiscordMemberExtensions.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using DSharpPlus;
|
||||||
|
using DSharpPlus.Entities;
|
||||||
|
|
||||||
|
namespace X10D.DSharpPlus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="DiscordMember" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class DiscordMemberExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a value indicating whether this member has the specified role.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="member">The member whose roles to search.</param>
|
||||||
|
/// <param name="role">The role for which to check.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true" /> if <paramref name="member" /> has the role; otherwise, <see langword="false" />.
|
||||||
|
/// </returns>
|
||||||
|
public static bool HasRole(this DiscordMember member, DiscordRole role)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(member);
|
||||||
|
ArgumentNullException.ThrowIfNull(role);
|
||||||
|
#else
|
||||||
|
if (member is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(role));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return member.Roles.Contains(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normalizes a <see cref="DiscordMember" /> so that the internal client is assured to be a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="member">The <see cref="DiscordMember" /> to normalize.</param>
|
||||||
|
/// <param name="client">The target client.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="DiscordMember" /> whose public values will match <paramref name="member" />, but whose internal client
|
||||||
|
/// is <paramref name="client" />.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// <para><paramref name="member" /> is <see langword="null" /></para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="client" /> is <see langword="null" /></para>
|
||||||
|
/// </exception>
|
||||||
|
public static async Task<DiscordMember> NormalizeClientAsync(this DiscordMember member, DiscordClient client)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(member);
|
||||||
|
ArgumentNullException.ThrowIfNull(client);
|
||||||
|
#else
|
||||||
|
if (member is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(client));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DiscordGuild guild = await member.Guild.NormalizeClientAsync(client).ConfigureAwait(false);
|
||||||
|
return await guild.GetMemberAsync(member.Id).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
89
X10D.DSharpPlus/src/DiscordMessageExtensions.cs
Normal file
89
X10D.DSharpPlus/src/DiscordMessageExtensions.cs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
using DSharpPlus;
|
||||||
|
using DSharpPlus.Entities;
|
||||||
|
|
||||||
|
namespace X10D.DSharpPlus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="DiscordMessage" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class DiscordMessageExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes this message after a specified delay.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to delete.</param>
|
||||||
|
/// <param name="delay">The delay before deletion.</param>
|
||||||
|
/// <param name="reason">The reason for the deletion.</param>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="message" /> is <see langword="null" />.</exception>
|
||||||
|
public static async Task DeleteAfterAsync(this DiscordMessage message, TimeSpan delay, string? reason = null)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(message);
|
||||||
|
#else
|
||||||
|
if (message is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(message));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
await Task.Delay(delay).ConfigureAwait(false);
|
||||||
|
await message.DeleteAsync(reason).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the message as created by this task after a specified delay.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The task whose <see cref="DiscordMessage" /> result should be deleted.</param>
|
||||||
|
/// <param name="delay">The delay before deletion.</param>
|
||||||
|
/// <param name="reason">The reason for the deletion.</param>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="task" /> is <see langword="null" />.</exception>
|
||||||
|
public static async Task DeleteAfterAsync(this Task<DiscordMessage> task, TimeSpan delay, string? reason = null)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(task);
|
||||||
|
#else
|
||||||
|
if (task is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(task));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DiscordMessage message = await task.ConfigureAwait(false);
|
||||||
|
await message.DeleteAfterAsync(delay, reason).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normalizes a <see cref="DiscordMessage" /> so that the internal client is assured to be a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The <see cref="DiscordMessage" /> to normalize.</param>
|
||||||
|
/// <param name="client">The target client.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="DiscordMessage" /> whose public values will match <paramref name="message" />, but whose internal client
|
||||||
|
/// is <paramref name="client" />.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// <para><paramref name="message" /> is <see langword="null" /></para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="client" /> is <see langword="null" /></para>
|
||||||
|
/// </exception>
|
||||||
|
public static async Task<DiscordMessage> NormalizeClientAsync(this DiscordMessage message, DiscordClient client)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(message);
|
||||||
|
ArgumentNullException.ThrowIfNull(client);
|
||||||
|
#else
|
||||||
|
if (message is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(client));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DiscordChannel channel = await message.Channel.NormalizeClientAsync(client).ConfigureAwait(false);
|
||||||
|
return await channel.GetMessageAsync(message.Id).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
158
X10D.DSharpPlus/src/DiscordUserExtensions.cs
Normal file
158
X10D.DSharpPlus/src/DiscordUserExtensions.cs
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
using DSharpPlus;
|
||||||
|
using DSharpPlus.Entities;
|
||||||
|
using DSharpPlus.Exceptions;
|
||||||
|
|
||||||
|
namespace X10D.DSharpPlus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="DiscordUser" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class DiscordUserExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current <see cref="DiscordUser" /> as a member of the specified guild.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">The user to transform.</param>
|
||||||
|
/// <param name="guild">The guild whose member list to search.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="DiscordMember" /> whose <see cref="DiscordMember.Guild" /> is equal to <paramref name="guild" />, or
|
||||||
|
/// <see langword="null" /> if this user is not in the specified <paramref name="guild" />.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// <para><paramref name="user" /> is <see langword="null" />.</para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="guild" /> is <see langword="null" />.</para>
|
||||||
|
/// </exception>
|
||||||
|
public static async Task<DiscordMember?> GetAsMemberOfAsync(this DiscordUser user, DiscordGuild guild)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
|
ArgumentNullException.ThrowIfNull(guild);
|
||||||
|
#else
|
||||||
|
if (user is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guild is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(guild));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (user is DiscordMember member && member.Guild == guild)
|
||||||
|
{
|
||||||
|
return member;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guild.Members.TryGetValue(user.Id, out member!))
|
||||||
|
{
|
||||||
|
return member;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await guild.GetMemberAsync(user.Id).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (NotFoundException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the user's username with the discriminator, in the format <c>username#discriminator</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">The user whose username and discriminator to retrieve.</param>
|
||||||
|
/// <returns>A string in the format <c>username#discriminator</c></returns>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="user" /> is <see langword="null" />.</exception>
|
||||||
|
public static string GetUsernameWithDiscriminator(this DiscordUser user)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
|
#else
|
||||||
|
if (user is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return $"{user.Username}#{user.Discriminator}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a value indicating whether the current user is in the specified guild.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">The user to check.</param>
|
||||||
|
/// <param name="guild">The guild whose member list to search.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true" /> if <paramref name="user" /> is a member of <paramref name="guild" />; otherwise,
|
||||||
|
/// <see langword="false" />.
|
||||||
|
/// </returns>
|
||||||
|
public static async Task<bool> IsInGuildAsync(this DiscordUser user, DiscordGuild guild)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
|
ArgumentNullException.ThrowIfNull(guild);
|
||||||
|
#else
|
||||||
|
if (user is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guild is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(guild));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (guild.Members.TryGetValue(user.Id, out _))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DiscordMember? member = await guild.GetMemberAsync(user.Id).ConfigureAwait(false);
|
||||||
|
return member is not null;
|
||||||
|
}
|
||||||
|
catch (NotFoundException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normalizes a <see cref="DiscordUser" /> so that the internal client is assured to be a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">The <see cref="DiscordUser" /> to normalize.</param>
|
||||||
|
/// <param name="client">The target client.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="DiscordUser" /> whose public values will match <paramref name="user" />, but whose internal client is
|
||||||
|
/// <paramref name="client" />.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// <para><paramref name="user" /> is <see langword="null" /></para>
|
||||||
|
/// -or-
|
||||||
|
/// <para><paramref name="client" /> is <see langword="null" /></para>
|
||||||
|
/// </exception>
|
||||||
|
public static async Task<DiscordUser> NormalizeClientAsync(this DiscordUser user, DiscordClient client)
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
|
ArgumentNullException.ThrowIfNull(client);
|
||||||
|
#else
|
||||||
|
if (user is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(client));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return await client.GetUserAsync(user.Id).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
329
X10D.DSharpPlus/src/MentionUtility.cs
Normal file
329
X10D.DSharpPlus/src/MentionUtility.cs
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace X10D.DSharpPlus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods for encoding and decoding Discord mention strings.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The implementations in this class are designed to resemble <c>MentionUtils</c> as provided by Discord.NET. The source is
|
||||||
|
/// available
|
||||||
|
/// <a href="https://github.com/discord-net/Discord.Net/blob/dev/src/Discord.Net.Core/Utils/MentionUtils.cs">
|
||||||
|
/// here
|
||||||
|
/// </a>.
|
||||||
|
/// </remarks>
|
||||||
|
public static class MentionUtility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a channel mention string built from the specified channel ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the channel to mention.</param>
|
||||||
|
/// <returns>A channel mention string in the format <c><#123></c>.</returns>
|
||||||
|
public static string MentionChannel(decimal id)
|
||||||
|
{
|
||||||
|
return $"<#{id:N0}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a channel mention string built from the specified channel ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the channel to mention.</param>
|
||||||
|
/// <returns>A channel mention string in the format <c><#123></c>.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static string MentionChannel(ulong id)
|
||||||
|
{
|
||||||
|
return $"<#{id}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a role mention string built from the specified channel ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the role to mention.</param>
|
||||||
|
/// <returns>A role mention string in the format <c><@&123></c>.</returns>
|
||||||
|
public static string MentionRole(decimal id)
|
||||||
|
{
|
||||||
|
return $"<@&{id:N0}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a role mention string built from the specified role ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the role to mention.</param>
|
||||||
|
/// <returns>A role mention string in the format <c><@&123></c>.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static string MentionRole(ulong id)
|
||||||
|
{
|
||||||
|
return $"<@&{id}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a user mention string built from the specified user ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the user to mention.</param>
|
||||||
|
/// <returns>A user mention string in the format <c><@123></c>.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static string MentionUser(decimal id)
|
||||||
|
{
|
||||||
|
return MentionUser(id, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a user mention string built from the specified user ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the user to mention.</param>
|
||||||
|
/// <param name="nickname">
|
||||||
|
/// <see langword="true" /> if the mention string should account for nicknames; otherwise, <see langword="false" />.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// A user mention string in the format <c><@!123></c> if <paramref name="nickname" /> is <see langword="true" />,
|
||||||
|
/// or in the format <c><@123></c> if <paramref name="nickname" /> is <see langword="false" />.
|
||||||
|
/// </returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static string MentionUser(decimal id, bool nickname)
|
||||||
|
{
|
||||||
|
return nickname ? $"<@!{id:N0}>" : $"<@{id:N0}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a user mention string built from the specified user ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the user to mention.</param>
|
||||||
|
/// <returns>A user mention string in the format <c><@123></c>.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static string MentionUser(ulong id)
|
||||||
|
{
|
||||||
|
return MentionUser(id, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a user mention string built from the specified user ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the user to mention.</param>
|
||||||
|
/// <param name="nickname">
|
||||||
|
/// <see langword="true" /> if the mention string should account for nicknames; otherwise, <see langword="false" />.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// A user mention string in the format <c><@!123></c> if <paramref name="nickname" /> is <see langword="true" />,
|
||||||
|
/// or in the format <c><@123></c> if <paramref name="nickname" /> is <see langword="false" />.
|
||||||
|
/// </returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static string MentionUser(ulong id, bool nickname)
|
||||||
|
{
|
||||||
|
return nickname ? $"<@!{id}>" : $"<@{id}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a provided channel mention string to a decimal value representing the channel ID. A return value indicates
|
||||||
|
/// whether the parse succeeded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">A string containing a mention string to parse, in the format <c><#123></c>.</param>
|
||||||
|
/// <param name="result">
|
||||||
|
/// When this method returns, contains the decimal value representing the channel ID contained within
|
||||||
|
/// <paramref name="value" />, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the
|
||||||
|
/// <paramref name="value" /> parameter is <see langword="null" /> or <see cref="string.Empty" />, is not of the correct
|
||||||
|
/// format, or represents a number less than <see cref="ulong.MinValue" /> or greater than <see cref="ulong.MaxValue" />.
|
||||||
|
/// </param>
|
||||||
|
/// <returns><see langword="true" /> if the parse was successful; otherwise, <see langword="false" />.</returns>
|
||||||
|
public static bool TryParseChannel(string? value, out decimal result)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Length < 3 || value[0] != '<' || value[1] != '#' || value[^1] != '>')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.Substring(2, value.Length - 3); // <#123>
|
||||||
|
if (!ulong.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out ulong actual))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = actual;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a provided channel mention string to a 64-bit unsigned integer representing the channel ID. A return value
|
||||||
|
/// indicates whether the parse succeeded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">A string containing a mention string to parse, in the format <c><#123></c>.</param>
|
||||||
|
/// <param name="result">
|
||||||
|
/// When this method returns, contains the 64-bit unsigned integer value representing the channel ID contained within
|
||||||
|
/// <paramref name="value" />, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the
|
||||||
|
/// <paramref name="value" /> parameter is <see langword="null" /> or <see cref="string.Empty" />, is not of the correct
|
||||||
|
/// format, or represents a number less than <see cref="ulong.MinValue" /> or greater than <see cref="ulong.MaxValue" />.
|
||||||
|
/// </param>
|
||||||
|
/// <returns><see langword="true" /> if the parse was successful; otherwise, <see langword="false" />.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static bool TryParseChannel(string? value, out ulong result)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Length < 3 || value[0] != '<' || value[1] != '#' || value[^1] != '>')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.Substring(2, value.Length - 3); // <#123>
|
||||||
|
return ulong.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a provided role mention string to a decimal value representing the role ID. A return value indicates whether
|
||||||
|
/// the parse succeeded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">A string containing a mention string to parse, in the format <c><@&123></c>.</param>
|
||||||
|
/// <param name="result">
|
||||||
|
/// When this method returns, contains the decimal value representing the role ID contained within
|
||||||
|
/// <paramref name="value" />, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the
|
||||||
|
/// <paramref name="value" /> parameter is <see langword="null" /> or <see cref="string.Empty" />, is not of the correct
|
||||||
|
/// format, or represents a number less than <see cref="ulong.MinValue" /> or greater than <see cref="ulong.MaxValue" />.
|
||||||
|
/// </param>
|
||||||
|
/// <returns><see langword="true" /> if the parse was successful; otherwise, <see langword="false" />.</returns>
|
||||||
|
public static bool TryParseRole(string? value, out decimal result)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Length < 4 || value[0] != '<' || value[1] != '@' || value[2] != '&' || value[^1] != '>')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.Substring(3, value.Length - 4); // <@&123>
|
||||||
|
if (!ulong.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out ulong actual))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = actual;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a provided role mention string to a 64-bit unsigned integer representing the role ID. A return value indicates
|
||||||
|
/// whether the parse succeeded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">A string containing a mention string to parse, in the format <c><@&123></c>.</param>
|
||||||
|
/// <param name="result">
|
||||||
|
/// When this method returns, contains the 64-bit unsigned integer value representing the role ID contained within
|
||||||
|
/// <paramref name="value" />, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the
|
||||||
|
/// <paramref name="value" /> parameter is <see langword="null" /> or <see cref="string.Empty" />, is not of the correct
|
||||||
|
/// format, or represents a number less than <see cref="ulong.MinValue" /> or greater than <see cref="ulong.MaxValue" />.
|
||||||
|
/// </param>
|
||||||
|
/// <returns><see langword="true" /> if the parse was successful; otherwise, <see langword="false" />.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static bool TryParseRole(string? value, out ulong result)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Length < 4 || value[0] != '<' || value[1] != '@' || value[2] != '&' || value[^1] != '>')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.Substring(3, value.Length - 4); // <@&123>
|
||||||
|
return ulong.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a provided user mention string to a decimal value representing the user ID. A return value indicates whether
|
||||||
|
/// the parse succeeded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">
|
||||||
|
/// A string containing a mention string to parse, in the format <c><@123></c> or <c><@!123></c>.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="result">
|
||||||
|
/// When this method returns, contains the decimal value representing the user ID contained within
|
||||||
|
/// <paramref name="value" />, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the
|
||||||
|
/// <paramref name="value" /> parameter is <see langword="null" /> or <see cref="string.Empty" />, is not of the correct
|
||||||
|
/// format, or represents a number less than <see cref="ulong.MinValue" /> or greater than <see cref="ulong.MaxValue" />.
|
||||||
|
/// </param>
|
||||||
|
/// <returns><see langword="true" /> if the parse was successful; otherwise, <see langword="false" />.</returns>
|
||||||
|
public static bool TryParseUser(string? value, out decimal result)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Length < 3 || value[0] != '<' || value[1] != '@' || value[^1] != '>')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Length >= 4 && value[2] == '!')
|
||||||
|
{
|
||||||
|
value = value.Substring(3, value.Length - 4); // <@!123>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = value.Substring(2, value.Length - 3); // <@123>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ulong.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out ulong actual))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = actual;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a provided user mention string to a 64-bit unsigned integer representing the user ID. A return value indicates
|
||||||
|
/// whether the parse succeeded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">
|
||||||
|
/// A string containing a mention string to parse, in the format <c><@123></c> or <c><@!123></c>.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="result">
|
||||||
|
/// When this method returns, contains the 64-bit unsigned integer value representing the user ID contained within
|
||||||
|
/// <paramref name="value" />, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the
|
||||||
|
/// <paramref name="value" /> parameter is <see langword="null" /> or <see cref="string.Empty" />, is not of the correct
|
||||||
|
/// format, or represents a number less than <see cref="ulong.MinValue" /> or greater than <see cref="ulong.MaxValue" />.
|
||||||
|
/// </param>
|
||||||
|
/// <returns><see langword="true" /> if the parse was successful; otherwise, <see langword="false" />.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static bool TryParseUser(string? value, out ulong result)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Length < 3 || value[0] != '<' || value[1] != '@' || value[^1] != '>')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Length >= 4 && value[2] == '!')
|
||||||
|
{
|
||||||
|
value = value.Substring(3, value.Length - 4); // <@!123>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = value.Substring(2, value.Length - 3); // <@123>
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulong.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result);
|
||||||
|
}
|
||||||
|
}
|
69
X10D.Hosting/X10D.Hosting.csproj
Normal file
69
X10D.Hosting/X10D.Hosting.csproj
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>net7.0;net6.0;netstandard2.1</TargetFrameworks>
|
||||||
|
<LangVersion>11.0</LangVersion>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<ImplicitUsings>true</ImplicitUsings>
|
||||||
|
<Authors>Oliver Booth</Authors>
|
||||||
|
<NeutralLanguage>en</NeutralLanguage>
|
||||||
|
<RepositoryUrl>https://github.com/oliverbooth/X10D</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<Description>Extension methods on crack.</Description>
|
||||||
|
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||||
|
<PackageIcon>branding_Icon.png</PackageIcon>
|
||||||
|
<PackageIconUrl/>
|
||||||
|
<PackageTags>dotnet extension-methods</PackageTags>
|
||||||
|
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/../CHANGELOG.md"))</PackageReleaseNotes>
|
||||||
|
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
|
||||||
|
<VersionPrefix>3.2.0</VersionPrefix>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
|
||||||
|
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(VersionSuffix)' != '' And '$(BuildNumber)' == ''">
|
||||||
|
<Version>$(VersionPrefix)-$(VersionSuffix)</Version>
|
||||||
|
<AssemblyVersion>$(VersionPrefix).0</AssemblyVersion>
|
||||||
|
<FileVersion>$(VersionPrefix).0</FileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(VersionSuffix)' != '' And '$(BuildNumber)' != ''">
|
||||||
|
<Version>$(VersionPrefix)-$(VersionSuffix).$(BuildNumber)</Version>
|
||||||
|
<AssemblyVersion>$(VersionPrefix).$(BuildNumber)</AssemblyVersion>
|
||||||
|
<FileVersion>$(VersionPrefix).$(BuildNumber)</FileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(VersionSuffix)' == ''">
|
||||||
|
<Version>$(VersionPrefix)</Version>
|
||||||
|
<AssemblyVersion>$(VersionPrefix).0</AssemblyVersion>
|
||||||
|
<FileVersion>$(VersionPrefix).0</FileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\branding_Icon.png">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath/>
|
||||||
|
</None>
|
||||||
|
<None Include="..\LICENSE.md">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath/>
|
||||||
|
</None>
|
||||||
|
<None Include="..\CHANGELOG.md">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath/>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
1
X10D.Hosting/src/Assembly.cs
Normal file
1
X10D.Hosting/src/Assembly.cs
Normal file
@ -0,0 +1 @@
|
|||||||
|
[assembly: CLSCompliant(true)]
|
@ -0,0 +1,35 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
namespace X10D.Hosting.DependencyInjection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dependency injection extensions for <see cref="IServiceCollection" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class ServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an <see cref="IHostedService" /> registration for the given type, while simultaneously adding it as a singleton.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The <see cref="IServiceCollection" /> to add the service to.</param>
|
||||||
|
/// <typeparam name="TService">The type of the service to add.</typeparam>
|
||||||
|
/// <returns>A reference to this instance after the operation has completed.</returns>
|
||||||
|
public static IServiceCollection AddHostedSingleton<TService>(this IServiceCollection services)
|
||||||
|
where TService : class, IHostedService
|
||||||
|
{
|
||||||
|
services.AddSingleton<TService>();
|
||||||
|
return services.AddSingleton<IHostedService, TService>(provider => provider.GetRequiredService<TService>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an <see cref="IHostedService" /> registration for the given type, while simultaneously adding it as a singleton.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The <see cref="IServiceCollection" /> to add the service to.</param>
|
||||||
|
/// <param name="type">The type of the service to register and the implementation to use.</param>
|
||||||
|
/// <returns>A reference to this instance after the operation has completed.</returns>
|
||||||
|
public static IServiceCollection AddHostedSingleton(this IServiceCollection services, Type type)
|
||||||
|
{
|
||||||
|
services.AddSingleton(type);
|
||||||
|
return services.AddSingleton(provider => (IHostedService)provider.GetRequiredService(type));
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ internal sealed class EmojiRegexGenerator : ISourceGenerator
|
|||||||
public void Initialize(GeneratorInitializationContext context)
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
{
|
{
|
||||||
string response = HttpClient.GetStringAsync(TwemojiRegexUrl).GetAwaiter().GetResult();
|
string response = HttpClient.GetStringAsync(TwemojiRegexUrl).GetAwaiter().GetResult();
|
||||||
|
var regex = new Regex(@"export default /(?<regex>.+)/g;", RegexOptions.Compiled, Regex.InfiniteMatchTimeout);
|
||||||
using var reader = new StringReader(response);
|
using var reader = new StringReader(response);
|
||||||
|
|
||||||
while (reader.ReadLine() is { } line)
|
while (reader.ReadLine() is { } line)
|
||||||
@ -26,7 +27,7 @@ internal sealed class EmojiRegexGenerator : ISourceGenerator
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Match match = Regex.Match(line, @"export default /(?<regex>.+)/g;");
|
Match match = regex.Match(line);
|
||||||
if (!match.Success)
|
if (!match.Success)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<LangVersion>10.0</LangVersion>
|
<LangVersion>11.0</LangVersion>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<ExcludeFromCodeCoverage>true</ExcludeFromCodeCoverage>
|
||||||
|
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<LangVersion>11.0</LangVersion>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<ExcludeFromCodeCoverage>true</ExcludeFromCodeCoverage>
|
||||||
|
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.1;net6.0</TargetFrameworks>
|
<TargetFrameworks>net7.0;net6.0;netcoreapp3.1</TargetFrameworks>
|
||||||
<LangVersion>10.0</LangVersion>
|
<LangVersion>11.0</LangVersion>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>true</ImplicitUsings>
|
<ImplicitUsings>true</ImplicitUsings>
|
||||||
|
<CoverletOutputFormat>json,cobertura</CoverletOutputFormat>
|
||||||
|
<CollectCoverage>true</CollectCoverage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0"/>
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0"/>
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0"/>
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10"/>
|
<PackageReference Include="Moq" Version="4.18.4"/>
|
||||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2"/>
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="3.0.2"/>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\X10D.Hosting\X10D.Hosting.csproj"/>
|
||||||
<ProjectReference Include="..\X10D\X10D.csproj"/>
|
<ProjectReference Include="..\X10D\X10D.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
42
X10D.Tests/src/Collections/ArrayTests.AsReadOnly.cs
Normal file
42
X10D.Tests/src/Collections/ArrayTests.AsReadOnly.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Collections;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
|
public partial class ArrayTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class AsReadOnlyTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void AsReadOnly_ShouldReturnReadOnlyCollection_WhenArrayIsNotNull()
|
||||||
|
{
|
||||||
|
int[] array = {1, 2, 3};
|
||||||
|
IReadOnlyCollection<int> result = array.AsReadOnly();
|
||||||
|
Assert.IsInstanceOfType(result, typeof(IReadOnlyCollection<int>));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AsReadOnly_ShouldThrowArgumentNullException_WhenArrayIsNull()
|
||||||
|
{
|
||||||
|
int[]? array = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array!.AsReadOnly());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AsReadOnly_ShouldReturnCorrectCount_WhenArrayIsNotEmpty()
|
||||||
|
{
|
||||||
|
int[] array = {1, 2, 3};
|
||||||
|
IReadOnlyCollection<int> result = array.AsReadOnly();
|
||||||
|
Assert.AreEqual(array.Length, result.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AsReadOnly_ShouldReturnEmptyCollection_WhenArrayIsEmpty()
|
||||||
|
{
|
||||||
|
int[] array = Array.Empty<int>();
|
||||||
|
IReadOnlyCollection<int> result = array.AsReadOnly();
|
||||||
|
Assert.AreEqual(0, result.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
X10D.Tests/src/Collections/ArrayTests.Clear.cs
Normal file
63
X10D.Tests/src/Collections/ArrayTests.Clear.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Collections;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
|
public partial class ArrayTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ClearTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Clear_ShouldClearTheArray()
|
||||||
|
{
|
||||||
|
var array = new int?[] {1, 2, 3, null, 4};
|
||||||
|
|
||||||
|
array.Clear();
|
||||||
|
|
||||||
|
Assert.IsTrue(array.All(x => x == null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Clear_ShouldDoNothing_WhenArrayIsEmpty()
|
||||||
|
{
|
||||||
|
int[] array = Array.Empty<int>();
|
||||||
|
array.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Clear_WithRange_ShouldClearTheSpecifiedRangeOfTheArray()
|
||||||
|
{
|
||||||
|
var array = new int?[] {1, 2, 3, null, 4};
|
||||||
|
|
||||||
|
array.Clear(1..4);
|
||||||
|
|
||||||
|
Assert.AreEqual(5, array.Length);
|
||||||
|
Assert.AreEqual(1, array[0]);
|
||||||
|
Assert.AreEqual(4, array[4]);
|
||||||
|
Assert.IsTrue(array[1..4].All(x => x == null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Clear_WithIndexAndLength_ShouldClearTheSpecifiedRangeOfTheArray()
|
||||||
|
{
|
||||||
|
var array = new int?[] {1, 2, 3, null, 4};
|
||||||
|
|
||||||
|
array.Clear(1, 3);
|
||||||
|
|
||||||
|
Assert.AreEqual(5, array.Length);
|
||||||
|
Assert.AreEqual(1, array[0]);
|
||||||
|
Assert.AreEqual(4, array[4]);
|
||||||
|
Assert.IsTrue(array[1..4].All(x => x == null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Clear_ShouldThrowArgumentNullException_WhenArrayIsNull()
|
||||||
|
{
|
||||||
|
int[] array = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array.Clear());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array.Clear(0, 1));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array.Clear(..1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,49 +1,8 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using X10D.Collections;
|
|
||||||
|
|
||||||
namespace X10D.Tests.Collections;
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class ArrayTests
|
public partial class ArrayTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
|
||||||
public void AsReadOnlyShouldBeReadOnly()
|
|
||||||
{
|
|
||||||
var array = new object[] {1, "f", true};
|
|
||||||
var readOnly = array.AsReadOnly();
|
|
||||||
Assert.IsNotNull(readOnly);
|
|
||||||
Assert.IsTrue(readOnly.Count == 3);
|
|
||||||
|
|
||||||
// ReSharper disable once ConvertTypeCheckToNullCheck
|
|
||||||
Assert.IsTrue(readOnly is IReadOnlyCollection<object>);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void AsReadOnlyNullShouldThrow()
|
|
||||||
{
|
|
||||||
object[]? array = null;
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(array!.AsReadOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CLSCompliant(false)]
|
|
||||||
[TestMethod]
|
|
||||||
[DataRow]
|
|
||||||
[DataRow(1)]
|
|
||||||
[DataRow(1, 2, 3)]
|
|
||||||
[DataRow(1, 2, 3, 4, 5)]
|
|
||||||
public void ClearShouldFillDefault(params int[] args)
|
|
||||||
{
|
|
||||||
args.Clear();
|
|
||||||
|
|
||||||
int[] clearedArray = Enumerable.Repeat(0, args.Length).ToArray();
|
|
||||||
CollectionAssert.AreEqual(clearedArray, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ClearNullShouldThrow()
|
|
||||||
{
|
|
||||||
int[]? array = null;
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(array!.Clear);
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => array!.Clear(0, 0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ namespace X10D.Tests.Collections;
|
|||||||
public class BoolListTests
|
public class BoolListTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Pack8Bit_Should_Pack_Correctly()
|
public void PackByte_Should_Pack_Correctly()
|
||||||
{
|
{
|
||||||
var array = new[] {true, false, true, false, true, false, true, false};
|
var array = new[] {true, false, true, false, true, false, true, false};
|
||||||
Assert.AreEqual(85, array.PackByte()); // 01010101
|
Assert.AreEqual(85, array.PackByte()); // 01010101
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using X10D.Collections;
|
using X10D.Collections;
|
||||||
|
|
||||||
namespace X10D.Tests.Collections;
|
namespace X10D.Tests.Collections;
|
||||||
@ -7,9 +8,10 @@ namespace X10D.Tests.Collections;
|
|||||||
public class ByteTests
|
public class ByteTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldUnpackToArrayCorrectly()
|
public void Unpack_ShouldUnpackToArrayCorrectly()
|
||||||
{
|
{
|
||||||
bool[] bits = ((byte)0b11010100).Unpack();
|
const byte value = 0b11010100;
|
||||||
|
bool[] bits = value.Unpack();
|
||||||
|
|
||||||
Assert.AreEqual(8, bits.Length);
|
Assert.AreEqual(8, bits.Length);
|
||||||
|
|
||||||
@ -24,10 +26,30 @@ public class ByteTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldUnpackToSpanCorrectly()
|
public void Unpack_ShouldUnpackToSpanCorrectly()
|
||||||
{
|
{
|
||||||
|
const byte value = 0b11010100;
|
||||||
Span<bool> bits = stackalloc bool[8];
|
Span<bool> bits = stackalloc bool[8];
|
||||||
((byte)0b11010100).Unpack(bits);
|
value.Unpack(bits);
|
||||||
|
|
||||||
|
Assert.IsFalse(bits[0]);
|
||||||
|
Assert.IsFalse(bits[1]);
|
||||||
|
Assert.IsTrue(bits[2]);
|
||||||
|
Assert.IsFalse(bits[3]);
|
||||||
|
Assert.IsTrue(bits[4]);
|
||||||
|
Assert.IsFalse(bits[5]);
|
||||||
|
Assert.IsTrue(bits[6]);
|
||||||
|
Assert.IsTrue(bits[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UnpackInternal_Fallback_ShouldUnpackToSpanCorrectly()
|
||||||
|
{
|
||||||
|
const byte value = 0b11010100;
|
||||||
|
Span<bool> bits = stackalloc bool[8];
|
||||||
|
value.UnpackInternal_Fallback(bits);
|
||||||
|
|
||||||
Assert.IsFalse(bits[0]);
|
Assert.IsFalse(bits[0]);
|
||||||
Assert.IsFalse(bits[1]);
|
Assert.IsFalse(bits[1]);
|
||||||
@ -40,18 +62,43 @@ public class ByteTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldRepackEqually()
|
public void UnpackInternal_Ssse3_ShouldUnpackToSpanCorrectly()
|
||||||
{
|
{
|
||||||
Assert.AreEqual(0b11010100, ((byte)0b11010100).Unpack().PackByte());
|
if (!Sse3.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte value = 0b11010100;
|
||||||
|
Span<bool> bits = stackalloc bool[8];
|
||||||
|
value.UnpackInternal_Ssse3(bits);
|
||||||
|
|
||||||
|
Assert.IsFalse(bits[0]);
|
||||||
|
Assert.IsFalse(bits[1]);
|
||||||
|
Assert.IsTrue(bits[2]);
|
||||||
|
Assert.IsFalse(bits[3]);
|
||||||
|
Assert.IsTrue(bits[4]);
|
||||||
|
Assert.IsFalse(bits[5]);
|
||||||
|
Assert.IsTrue(bits[6]);
|
||||||
|
Assert.IsTrue(bits[7]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Unpack_ShouldRepackEqually()
|
||||||
|
{
|
||||||
|
const byte value = 0b11010100;
|
||||||
|
Assert.AreEqual(value, value.Unpack().PackByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldThrow_GivenTooSmallSpan()
|
public void Unpack_ShouldThrow_GivenTooSmallSpan()
|
||||||
{
|
{
|
||||||
Assert.ThrowsException<ArgumentException>(() =>
|
Assert.ThrowsException<ArgumentException>(() =>
|
||||||
{
|
{
|
||||||
|
const byte value = 0b11010100;
|
||||||
Span<bool> bits = stackalloc bool[0];
|
Span<bool> bits = stackalloc bool[0];
|
||||||
((byte)0b11010100).Unpack(bits);
|
value.Unpack(bits);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
using X10D.Collections;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
|
public partial class CollectionTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ClearAndDisposeAllTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ClearAndDisposeAll_ShouldClearAndDisposeAllItems_WhenCalledWithValidList()
|
||||||
|
{
|
||||||
|
var mock1 = new Mock<IDisposable>();
|
||||||
|
var mock2 = new Mock<IDisposable>();
|
||||||
|
var mock3 = new Mock<IDisposable>();
|
||||||
|
var list = new List<IDisposable> {mock1.Object, mock2.Object, mock3.Object};
|
||||||
|
|
||||||
|
list.ClearAndDisposeAll();
|
||||||
|
|
||||||
|
mock1.Verify(i => i.Dispose(), Times.Once);
|
||||||
|
mock2.Verify(i => i.Dispose(), Times.Once);
|
||||||
|
mock3.Verify(i => i.Dispose(), Times.Once);
|
||||||
|
Assert.AreEqual(0, list.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ClearAndDisposeAll_ShouldThrowArgumentNullException_WhenCalledWithNullList()
|
||||||
|
{
|
||||||
|
List<IDisposable>? list = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => list!.ClearAndDisposeAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ClearAndDisposeAll_ShouldThrowInvalidOperationException_WhenCalledWithReadOnlyList()
|
||||||
|
{
|
||||||
|
var mock = new Mock<IDisposable>();
|
||||||
|
var list = new ReadOnlyCollection<IDisposable>(new List<IDisposable> {mock.Object});
|
||||||
|
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => list.ClearAndDisposeAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
using X10D.Collections;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
|
public partial class CollectionTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ClearAndDisposeAllAsyncTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ClearAndDisposeAllAsync_ShouldClearAndDisposeAllItems_WhenCalledWithValidList()
|
||||||
|
{
|
||||||
|
var mock1 = new Mock<IAsyncDisposable>();
|
||||||
|
var mock2 = new Mock<IAsyncDisposable>();
|
||||||
|
var mock3 = new Mock<IAsyncDisposable>();
|
||||||
|
var list = new List<IAsyncDisposable> {mock1.Object, mock2.Object, mock3.Object};
|
||||||
|
|
||||||
|
await list.ClearAndDisposeAllAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
mock1.Verify(i => i.DisposeAsync(), Times.Once);
|
||||||
|
mock2.Verify(i => i.DisposeAsync(), Times.Once);
|
||||||
|
mock3.Verify(i => i.DisposeAsync(), Times.Once);
|
||||||
|
Assert.AreEqual(0, list.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ClearAndDisposeAllAsync_ShouldThrowArgumentNullException_WhenCalledWithNullList()
|
||||||
|
{
|
||||||
|
List<IAsyncDisposable>? list = null;
|
||||||
|
await Assert.ThrowsExceptionAsync<ArgumentNullException>(list!.ClearAndDisposeAllAsync).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ClearAndDisposeAllAsync_ShouldThrowInvalidOperationException_WhenCalledWithReadOnlyList()
|
||||||
|
{
|
||||||
|
var mock = new Mock<IAsyncDisposable>();
|
||||||
|
var list = new ReadOnlyCollection<IAsyncDisposable>(new List<IAsyncDisposable> {mock.Object});
|
||||||
|
|
||||||
|
await Assert.ThrowsExceptionAsync<InvalidOperationException>(list.ClearAndDisposeAllAsync).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,77 +1,8 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using X10D.Collections;
|
|
||||||
|
|
||||||
namespace X10D.Tests.Collections;
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class CollectionTests
|
public partial class CollectionTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
|
||||||
public void ClearAndDisposeAll_ShouldDispose_GivenCollection()
|
|
||||||
{
|
|
||||||
var collection = new List<Disposable> {new(), new(), new()};
|
|
||||||
var copy = new List<Disposable>(collection);
|
|
||||||
|
|
||||||
collection.ClearAndDisposeAll();
|
|
||||||
|
|
||||||
Assert.IsTrue(copy.All(x => x.IsDisposed));
|
|
||||||
Assert.AreEqual(0, collection.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public async Task ClearAndDisposeAllAsync_ShouldDispose_GivenCollection()
|
|
||||||
{
|
|
||||||
var collection = new List<Disposable> {new(), new(), new()};
|
|
||||||
var copy = new List<Disposable>(collection);
|
|
||||||
|
|
||||||
await collection.ClearAndDisposeAllAsync();
|
|
||||||
|
|
||||||
Assert.IsTrue(copy.All(x => x.IsDisposed));
|
|
||||||
Assert.AreEqual(0, collection.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ClearAndDisposeAll_ShouldThrow_GivenNull()
|
|
||||||
{
|
|
||||||
List<Disposable>? collection = null;
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => collection!.ClearAndDisposeAll());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ClearAndDisposeAllAsync_ShouldThrow_GivenNull()
|
|
||||||
{
|
|
||||||
List<Disposable>? collection = null;
|
|
||||||
Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await collection!.ClearAndDisposeAllAsync());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ClearAndDisposeAll_ShouldThrow_GivenReadOnlyCollection()
|
|
||||||
{
|
|
||||||
var collection = new List<Disposable>().AsReadOnly();
|
|
||||||
Assert.ThrowsException<InvalidOperationException>(() => collection.ClearAndDisposeAll());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ClearAndDisposeAllAsync_ShouldThrow_GivenReadOnlyCollection()
|
|
||||||
{
|
|
||||||
var collection = new List<Disposable>().AsReadOnly();
|
|
||||||
Assert.ThrowsExceptionAsync<InvalidOperationException>(async () => await collection.ClearAndDisposeAllAsync());
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Disposable : IDisposable, IAsyncDisposable
|
|
||||||
{
|
|
||||||
public bool IsDisposed { get; private set; }
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Assert.IsTrue(IsDisposed = true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable CS1998
|
|
||||||
public async ValueTask DisposeAsync()
|
|
||||||
#pragma warning restore CS1998
|
|
||||||
{
|
|
||||||
Assert.IsTrue(IsDisposed = true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ namespace X10D.Tests.Collections;
|
|||||||
public class DictionaryTests
|
public class DictionaryTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void AddOrUpdate_ShouldAddNewKey_IfNotExists()
|
public void AddOrUpdate_ShouldAddNewKey_IfNotExists_GivenConcreteDictionary()
|
||||||
{
|
{
|
||||||
var dictionary = new Dictionary<int, string>();
|
var dictionary = new Dictionary<int, string>();
|
||||||
Assert.IsFalse(dictionary.ContainsKey(1));
|
Assert.IsFalse(dictionary.ContainsKey(1));
|
||||||
@ -32,7 +32,32 @@ public class DictionaryTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void AddOrUpdate_ShouldUpdateKey_IfExists()
|
public void AddOrUpdate_ShouldAddNewKey_IfNotExists_GivenIDictionary()
|
||||||
|
{
|
||||||
|
IDictionary<int, string> dictionary = new Dictionary<int, string>();
|
||||||
|
Assert.IsFalse(dictionary.ContainsKey(1));
|
||||||
|
|
||||||
|
dictionary.AddOrUpdate(1, "one", (_, _) => string.Empty);
|
||||||
|
Assert.IsTrue(dictionary.ContainsKey(1));
|
||||||
|
Assert.AreEqual("one", dictionary[1]);
|
||||||
|
|
||||||
|
dictionary.Clear();
|
||||||
|
Assert.IsFalse(dictionary.ContainsKey(1));
|
||||||
|
|
||||||
|
dictionary.AddOrUpdate(1, _ => "one", (_, _) => string.Empty);
|
||||||
|
Assert.IsTrue(dictionary.ContainsKey(1));
|
||||||
|
Assert.AreEqual("one", dictionary[1]);
|
||||||
|
|
||||||
|
dictionary.Clear();
|
||||||
|
Assert.IsFalse(dictionary.ContainsKey(1));
|
||||||
|
|
||||||
|
dictionary.AddOrUpdate(1, (_, _) => "one", (_, _, _) => string.Empty, 0);
|
||||||
|
Assert.IsTrue(dictionary.ContainsKey(1));
|
||||||
|
Assert.AreEqual("one", dictionary[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddOrUpdate_ShouldUpdateKey_IfExists_GivenConcreteDirection()
|
||||||
{
|
{
|
||||||
var dictionary = new Dictionary<int, string> {[1] = "one"};
|
var dictionary = new Dictionary<int, string> {[1] = "one"};
|
||||||
Assert.IsTrue(dictionary.ContainsKey(1));
|
Assert.IsTrue(dictionary.ContainsKey(1));
|
||||||
@ -60,7 +85,35 @@ public class DictionaryTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void AddOrUpdate_ShouldThrow_GivenNullDictionary()
|
public void AddOrUpdate_ShouldUpdateKey_IfExists_GivenIDictionary()
|
||||||
|
{
|
||||||
|
IDictionary<int, string> dictionary = new Dictionary<int, string> {[1] = "one"};
|
||||||
|
Assert.IsTrue(dictionary.ContainsKey(1));
|
||||||
|
Assert.AreEqual("one", dictionary[1]);
|
||||||
|
|
||||||
|
dictionary.AddOrUpdate(1, string.Empty, (_, _) => "two");
|
||||||
|
Assert.IsTrue(dictionary.ContainsKey(1));
|
||||||
|
Assert.AreEqual("two", dictionary[1]);
|
||||||
|
|
||||||
|
dictionary.Clear();
|
||||||
|
Assert.IsFalse(dictionary.ContainsKey(1));
|
||||||
|
dictionary[1] = "one";
|
||||||
|
|
||||||
|
dictionary.AddOrUpdate(1, _ => string.Empty, (_, _) => "two");
|
||||||
|
Assert.IsTrue(dictionary.ContainsKey(1));
|
||||||
|
Assert.AreEqual("two", dictionary[1]);
|
||||||
|
|
||||||
|
dictionary.Clear();
|
||||||
|
Assert.IsFalse(dictionary.ContainsKey(1));
|
||||||
|
dictionary[1] = "one";
|
||||||
|
|
||||||
|
dictionary.AddOrUpdate(1, (_, _) => string.Empty, (_, _, _) => "two", 0);
|
||||||
|
Assert.IsTrue(dictionary.ContainsKey(1));
|
||||||
|
Assert.AreEqual("two", dictionary[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddOrUpdate_ShouldThrow_GivenNullDictionary_GivenConcreteDictionary()
|
||||||
{
|
{
|
||||||
Dictionary<int, string>? dictionary = null;
|
Dictionary<int, string>? dictionary = null;
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => dictionary!.AddOrUpdate(1, string.Empty, (_, _) => string.Empty));
|
Assert.ThrowsException<ArgumentNullException>(() => dictionary!.AddOrUpdate(1, string.Empty, (_, _) => string.Empty));
|
||||||
@ -71,7 +124,18 @@ public class DictionaryTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void AddOrUpdate_ShouldThrow_GivenNullUpdateValueFactory()
|
public void AddOrUpdate_ShouldThrow_GivenNullDictionary_GivenIDictionary()
|
||||||
|
{
|
||||||
|
IDictionary<int, string>? dictionary = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => dictionary!.AddOrUpdate(1, string.Empty, (_, _) => string.Empty));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() =>
|
||||||
|
dictionary!.AddOrUpdate(1, _ => string.Empty, (_, _) => string.Empty));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() =>
|
||||||
|
dictionary!.AddOrUpdate(1, (_, _) => string.Empty, (_, _, _) => string.Empty, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddOrUpdate_ShouldThrow_GivenNullUpdateValueFactory_GivenConcreteDictionary()
|
||||||
{
|
{
|
||||||
var dictionary = new Dictionary<int, string>();
|
var dictionary = new Dictionary<int, string>();
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => dictionary.AddOrUpdate(1, string.Empty, null!));
|
Assert.ThrowsException<ArgumentNullException>(() => dictionary.AddOrUpdate(1, string.Empty, null!));
|
||||||
@ -80,7 +144,16 @@ public class DictionaryTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void AddOrUpdate_ShouldThrow_GivenNullAddValueFactory()
|
public void AddOrUpdate_ShouldThrow_GivenNullUpdateValueFactory_GivenIDictionary()
|
||||||
|
{
|
||||||
|
IDictionary<int, string> dictionary = new Dictionary<int, string>();
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => dictionary.AddOrUpdate(1, string.Empty, null!));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => dictionary.AddOrUpdate(1, _ => string.Empty, null!));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => dictionary.AddOrUpdate(1, (_, _) => string.Empty, null!, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddOrUpdate_ShouldThrow_GivenNullAddValueFactory_GivenConcreteDictionary()
|
||||||
{
|
{
|
||||||
var dictionary = new Dictionary<int, string>();
|
var dictionary = new Dictionary<int, string>();
|
||||||
Func<int, string>? addValueFactory = null;
|
Func<int, string>? addValueFactory = null;
|
||||||
@ -88,6 +161,15 @@ public class DictionaryTests
|
|||||||
Assert.ThrowsException<ArgumentNullException>(() => dictionary.AddOrUpdate(1, null!, (_, _, _) => "one", 0));
|
Assert.ThrowsException<ArgumentNullException>(() => dictionary.AddOrUpdate(1, null!, (_, _, _) => "one", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddOrUpdate_ShouldThrow_GivenNullAddValueFactory_GivenIDictionary()
|
||||||
|
{
|
||||||
|
IDictionary<int, string> dictionary = new Dictionary<int, string>();
|
||||||
|
Func<int, string>? addValueFactory = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => dictionary.AddOrUpdate(1, addValueFactory!, (_, _) => "one"));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => dictionary.AddOrUpdate(1, null!, (_, _, _) => "one", 0));
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ToConnectionString_ShouldReturnConnectionString()
|
public void ToConnectionString_ShouldReturnConnectionString()
|
||||||
{
|
{
|
||||||
|
34
X10D.Tests/src/Collections/EnumerableTests.DisposeAll.cs
Normal file
34
X10D.Tests/src/Collections/EnumerableTests.DisposeAll.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
using X10D.Collections;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
|
public partial class EnumerableTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DisposeAllTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void DisposeAll_ShouldDisposeAllItems_WhenCalledWithValidList()
|
||||||
|
{
|
||||||
|
var mock1 = new Mock<IDisposable>();
|
||||||
|
var mock2 = new Mock<IDisposable>();
|
||||||
|
var mock3 = new Mock<IDisposable>();
|
||||||
|
var list = new List<IDisposable> {mock1.Object, mock2.Object, null!, mock3.Object};
|
||||||
|
|
||||||
|
list.DisposeAll();
|
||||||
|
|
||||||
|
mock1.Verify(i => i.Dispose(), Times.Once);
|
||||||
|
mock2.Verify(i => i.Dispose(), Times.Once);
|
||||||
|
mock3.Verify(i => i.Dispose(), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void DisposeAll_ShouldThrowArgumentNullException_WhenCalledWithNullList()
|
||||||
|
{
|
||||||
|
List<IDisposable>? list = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => list!.DisposeAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
using X10D.Collections;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
|
public partial class EnumerableTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DisposeAllAsyncTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public async Task DisposeAllAsync_ShouldDisposeAllItems_WhenCalledWithValidList()
|
||||||
|
{
|
||||||
|
var mock1 = new Mock<IAsyncDisposable>();
|
||||||
|
var mock2 = new Mock<IAsyncDisposable>();
|
||||||
|
var mock3 = new Mock<IAsyncDisposable>();
|
||||||
|
var list = new List<IAsyncDisposable> {mock1.Object, mock2.Object, null!, mock3.Object};
|
||||||
|
|
||||||
|
await list.DisposeAllAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
mock1.Verify(i => i.DisposeAsync(), Times.Once);
|
||||||
|
mock2.Verify(i => i.DisposeAsync(), Times.Once);
|
||||||
|
mock3.Verify(i => i.DisposeAsync(), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task DisposeAllAsync_ShouldThrowArgumentNullException_WhenCalledWithNullList()
|
||||||
|
{
|
||||||
|
List<IAsyncDisposable>? list = null;
|
||||||
|
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => list!.DisposeAllAsync()).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,39 +1,112 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using X10D.Collections;
|
using X10D.Collections;
|
||||||
|
using X10D.Core;
|
||||||
|
|
||||||
namespace X10D.Tests.Collections;
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class EnumerableTests
|
public partial class EnumerableTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void DisposeAll_ShouldDispose_GivenCollection()
|
public void CountWhereNot_ShouldReturnCorrectCount_GivenSequence()
|
||||||
{
|
{
|
||||||
var collection = new List<Disposable> {new(), new(), new()};
|
var enumerable = new[] {2, 4, 6, 7, 8, 9, 10};
|
||||||
collection.DisposeAll();
|
int count = enumerable.CountWhereNot(x => x % 2 == 0);
|
||||||
Assert.IsTrue(collection.All(x => x.IsDisposed));
|
Assert.AreEqual(2, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public async Task DisposeAllAsync_ShouldDispose_GivenCollection()
|
public void CountWhereNot_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
{
|
{
|
||||||
var collection = new List<Disposable> {new(), new(), new()};
|
Assert.ThrowsException<ArgumentNullException>(() => ((IEnumerable<int>?)null)!.CountWhereNot(x => x % 2 == 0));
|
||||||
await collection.DisposeAllAsync();
|
|
||||||
Assert.IsTrue(collection.All(x => x.IsDisposed));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void DisposeAll_ShouldThrow_GivenNull()
|
public void CountWhereNot_ShouldThrowArgumentNullException_GivenNullPredicate()
|
||||||
{
|
{
|
||||||
List<Disposable>? collection = null;
|
Assert.ThrowsException<ArgumentNullException>(() => Enumerable.Empty<int>().CountWhereNot(null!));
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => collection!.DisposeAll());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public async Task DisposeAllAsync_ShouldThrow_GivenNull()
|
public void CountWhereNot_ShouldThrowOverflowException_GivenLargeSource()
|
||||||
{
|
{
|
||||||
List<Disposable>? collection = null;
|
IEnumerable<byte> GetValues()
|
||||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await collection!.DisposeAllAsync());
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
yield return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once IteratorNeverReturns
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.ThrowsException<OverflowException>(() => GetValues().CountWhereNot(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNot_ShouldReturnCorrectElements_GivenSequence()
|
||||||
|
{
|
||||||
|
var enumerable = new[] {2, 4, 6, 7, 8, 9, 10};
|
||||||
|
int result = enumerable.FirstWhereNot(x => x % 2 == 0);
|
||||||
|
Assert.AreEqual(7, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNot_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((IEnumerable<int>?)null)!.FirstWhereNot(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNot_ShouldThrowArgumentNullException_GivenNullPredicate()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => Enumerable.Range(0, 1).FirstWhereNot(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNot_ShouldThrowInvalidOperationException_GivenEmptySource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => Enumerable.Empty<int>().FirstWhereNot(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNot_ShouldThrowInvalidOperationException_GivenSourceWithNoMatchingElements()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => 2.AsArrayValue().FirstWhereNot(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNotOrDefault_ShouldReturnCorrectElements_GivenSequence()
|
||||||
|
{
|
||||||
|
var enumerable = new[] {2, 4, 6, 7, 8, 9, 10};
|
||||||
|
int result = enumerable.FirstWhereNotOrDefault(x => x % 2 == 0);
|
||||||
|
Assert.AreEqual(7, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNotOrDefault_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((IEnumerable<int>?)null)!.FirstWhereNotOrDefault(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNotOrDefault_ShouldThrowArgumentNullException_GivenNullPredicate()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => Enumerable.Empty<int>().FirstWhereNotOrDefault(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNotOrDefault_ShouldReturnDefault_GivenEmptySource()
|
||||||
|
{
|
||||||
|
int result = Enumerable.Empty<int>().FirstWhereNotOrDefault(x => x % 2 == 0);
|
||||||
|
Assert.AreEqual(default, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FirstWhereNotOrDefault_ShouldReturnDefault_GivenSourceWithNoMatchingElements()
|
||||||
|
{
|
||||||
|
int result = 2.AsArrayValue().FirstWhereNotOrDefault(x => x % 2 == 0);
|
||||||
|
Assert.AreEqual(default, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@ -94,6 +167,72 @@ public class EnumerableTests
|
|||||||
Assert.ThrowsException<ArgumentNullException>(() => source.ForEach(null!));
|
Assert.ThrowsException<ArgumentNullException>(() => source.ForEach(null!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNot_ShouldReturnCorrectElements_GivenSequence()
|
||||||
|
{
|
||||||
|
var enumerable = new[] {2, 4, 6, 7, 8, 9, 10};
|
||||||
|
int result = enumerable.LastWhereNot(x => x % 2 == 0);
|
||||||
|
Assert.AreEqual(9, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNot_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((IEnumerable<int>?)null)!.LastWhereNot(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNot_ShouldThrowArgumentNullException_GivenNullPredicate()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => Array.Empty<int>().LastWhereNot(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNot_ShouldThrowInvalidOperationException_GivenEmptySource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => Array.Empty<int>().LastWhereNot(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNot_ShouldThrowInvalidOperationException_GivenSourceWithNoMatchingElements()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => 2.AsArrayValue().LastWhereNot(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNotOrDefault_ShouldReturnCorrectElements_GivenSequence()
|
||||||
|
{
|
||||||
|
var enumerable = new[] {2, 4, 6, 7, 8, 9, 10};
|
||||||
|
int result = enumerable.LastWhereNotOrDefault(x => x % 2 == 0);
|
||||||
|
Assert.AreEqual(9, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNotOrDefault_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((IEnumerable<int>?)null)!.LastWhereNotOrDefault(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNotOrDefault_ShouldThrowArgumentNullException_GivenNullPredicate()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => Array.Empty<int>().LastWhereNotOrDefault(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNotOrDefault_ShouldReturnDefault_GivenEmptySource()
|
||||||
|
{
|
||||||
|
int result = Array.Empty<int>().LastWhereNotOrDefault(x => x % 2 == 0);
|
||||||
|
Assert.AreEqual(default, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LastWhereNotOrDefault_ShouldReturnDefault_GivenSourceWithNoMatchingElements()
|
||||||
|
{
|
||||||
|
int result = 2.AsArrayValue().LastWhereNotOrDefault(x => x % 2 == 0);
|
||||||
|
Assert.AreEqual(default, result);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Shuffled_ShouldThrow_GivenNull()
|
public void Shuffled_ShouldThrow_GivenNull()
|
||||||
{
|
{
|
||||||
@ -112,25 +251,56 @@ public class EnumerableTests
|
|||||||
CollectionAssert.AreNotEqual(array, shuffled);
|
CollectionAssert.AreNotEqual(array, shuffled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WhereNot_ShouldReturnCorrectElements_GivenSequence()
|
||||||
|
{
|
||||||
|
var enumerable = new[] {2, 4, 6, 7, 8, 9, 10};
|
||||||
|
IEnumerable<int> result = enumerable.WhereNot(x => x % 2 == 0);
|
||||||
|
CollectionAssert.AreEqual(new[] {7, 9}, result.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WhereNot_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((IEnumerable<int>?)null)!.WhereNot(x => x % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WhereNot_ShouldThrowArgumentNullException_GivenNullPredicate()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => Enumerable.Empty<int>().WhereNot(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WhereNotNull_ShouldContainNoNullElements()
|
||||||
|
{
|
||||||
|
object?[] array = Enumerable.Repeat(new object(), 10).ToArray();
|
||||||
|
array[1] = null;
|
||||||
|
array[2] = null;
|
||||||
|
array[8] = null;
|
||||||
|
array[9] = null;
|
||||||
|
|
||||||
|
const int expectedCount = 6;
|
||||||
|
var actualCount = 0;
|
||||||
|
|
||||||
|
foreach (object o in array.WhereNotNull())
|
||||||
|
{
|
||||||
|
Assert.IsNotNull(o);
|
||||||
|
actualCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedCount, actualCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WhereNotNull_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<string> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.WhereNotNull());
|
||||||
|
}
|
||||||
|
|
||||||
private class DummyClass
|
private class DummyClass
|
||||||
{
|
{
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Disposable : IDisposable, IAsyncDisposable
|
|
||||||
{
|
|
||||||
public bool IsDisposed { get; private set; }
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Assert.IsTrue(IsDisposed = true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable CS1998
|
|
||||||
public async ValueTask DisposeAsync()
|
|
||||||
#pragma warning restore CS1998
|
|
||||||
{
|
|
||||||
Assert.IsTrue(IsDisposed = true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using X10D.Collections;
|
using X10D.Collections;
|
||||||
|
|
||||||
namespace X10D.Tests.Collections;
|
namespace X10D.Tests.Collections;
|
||||||
@ -7,9 +8,10 @@ namespace X10D.Tests.Collections;
|
|||||||
public class Int16Tests
|
public class Int16Tests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldUnpackToArrayCorrectly()
|
public void Unpack_ShouldUnpackToArrayCorrectly()
|
||||||
{
|
{
|
||||||
bool[] bits = ((short)0b11010100).Unpack();
|
const short value = 0b11010100;
|
||||||
|
bool[] bits = value.Unpack();
|
||||||
|
|
||||||
Assert.AreEqual(16, bits.Length);
|
Assert.AreEqual(16, bits.Length);
|
||||||
|
|
||||||
@ -29,10 +31,11 @@ public class Int16Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldUnpackToSpanCorrectly()
|
public void Unpack_ShouldUnpackToSpanCorrectly()
|
||||||
{
|
{
|
||||||
|
const short value = 0b11010100;
|
||||||
Span<bool> bits = stackalloc bool[16];
|
Span<bool> bits = stackalloc bool[16];
|
||||||
((short)0b11010100).Unpack(bits);
|
value.Unpack(bits);
|
||||||
|
|
||||||
Assert.IsFalse(bits[0]);
|
Assert.IsFalse(bits[0]);
|
||||||
Assert.IsFalse(bits[1]);
|
Assert.IsFalse(bits[1]);
|
||||||
@ -50,18 +53,71 @@ public class Int16Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldRepackEqually()
|
public void Unpack_ShouldUnpackToSpanCorrectly_GivenFallbackImplementation()
|
||||||
{
|
{
|
||||||
Assert.AreEqual(0b11010100, ((short)0b11010100).Unpack().PackInt16());
|
const short value = 0b11010100;
|
||||||
|
Span<bool> bits = stackalloc bool[16];
|
||||||
|
value.UnpackInternal_Fallback(bits);
|
||||||
|
|
||||||
|
Assert.IsFalse(bits[0]);
|
||||||
|
Assert.IsFalse(bits[1]);
|
||||||
|
Assert.IsTrue(bits[2]);
|
||||||
|
Assert.IsFalse(bits[3]);
|
||||||
|
Assert.IsTrue(bits[4]);
|
||||||
|
Assert.IsFalse(bits[5]);
|
||||||
|
Assert.IsTrue(bits[6]);
|
||||||
|
Assert.IsTrue(bits[7]);
|
||||||
|
|
||||||
|
for (var index = 8; index < 16; index++)
|
||||||
|
{
|
||||||
|
Assert.IsFalse(bits[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
|
[TestMethod]
|
||||||
|
public void UnpackInternal_Ssse3_ShouldUnpackToSpanCorrectly()
|
||||||
|
{
|
||||||
|
if (!Sse3.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const short value = 0b11010100;
|
||||||
|
Span<bool> bits = stackalloc bool[16];
|
||||||
|
value.UnpackInternal_Ssse3(bits);
|
||||||
|
|
||||||
|
Assert.IsFalse(bits[0]);
|
||||||
|
Assert.IsFalse(bits[1]);
|
||||||
|
Assert.IsTrue(bits[2]);
|
||||||
|
Assert.IsFalse(bits[3]);
|
||||||
|
Assert.IsTrue(bits[4]);
|
||||||
|
Assert.IsFalse(bits[5]);
|
||||||
|
Assert.IsTrue(bits[6]);
|
||||||
|
Assert.IsTrue(bits[7]);
|
||||||
|
|
||||||
|
for (var index = 8; index < 16; index++)
|
||||||
|
{
|
||||||
|
Assert.IsFalse(bits[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Unpack_ShouldRepackEqually()
|
||||||
|
{
|
||||||
|
const short value = 0b11010100;
|
||||||
|
Assert.AreEqual(value, value.Unpack().PackInt16());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldThrow_GivenTooSmallSpan()
|
public void Unpack_ShouldThrow_GivenTooSmallSpan()
|
||||||
{
|
{
|
||||||
Assert.ThrowsException<ArgumentException>(() =>
|
Assert.ThrowsException<ArgumentException>(() =>
|
||||||
{
|
{
|
||||||
|
const short value = 0b11010100;
|
||||||
Span<bool> bits = stackalloc bool[0];
|
Span<bool> bits = stackalloc bool[0];
|
||||||
((short)0b11010100).Unpack(bits);
|
value.Unpack(bits);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using X10D.Collections;
|
using X10D.Collections;
|
||||||
|
|
||||||
namespace X10D.Tests.Collections;
|
namespace X10D.Tests.Collections;
|
||||||
@ -7,9 +8,10 @@ namespace X10D.Tests.Collections;
|
|||||||
public class Int32Tests
|
public class Int32Tests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldUnpackToArrayCorrectly()
|
public void Unpack_ShouldUnpackToArrayCorrectly()
|
||||||
{
|
{
|
||||||
bool[] bits = 0b11010100.Unpack();
|
const int value = 0b11010100;
|
||||||
|
bool[] bits = value.Unpack();
|
||||||
|
|
||||||
Assert.AreEqual(32, bits.Length);
|
Assert.AreEqual(32, bits.Length);
|
||||||
|
|
||||||
@ -29,10 +31,11 @@ public class Int32Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldUnpackToSpanCorrectly()
|
public void Unpack_ShouldUnpackToSpanCorrectly()
|
||||||
{
|
{
|
||||||
|
const int value = 0b11010100;
|
||||||
Span<bool> bits = stackalloc bool[32];
|
Span<bool> bits = stackalloc bool[32];
|
||||||
0b11010100.Unpack(bits);
|
value.Unpack(bits);
|
||||||
|
|
||||||
Assert.IsFalse(bits[0]);
|
Assert.IsFalse(bits[0]);
|
||||||
Assert.IsFalse(bits[1]);
|
Assert.IsFalse(bits[1]);
|
||||||
@ -50,18 +53,98 @@ public class Int32Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldRepackEqually()
|
public void UnpackInternal_Fallback_ShouldUnpackToSpanCorrectly()
|
||||||
{
|
{
|
||||||
Assert.AreEqual(0b11010100, 0b11010100.Unpack().PackInt32());
|
const int value = 0b11010100;
|
||||||
|
Span<bool> bits = stackalloc bool[32];
|
||||||
|
value.UnpackInternal_Fallback(bits);
|
||||||
|
|
||||||
|
Assert.IsFalse(bits[0]);
|
||||||
|
Assert.IsFalse(bits[1]);
|
||||||
|
Assert.IsTrue(bits[2]);
|
||||||
|
Assert.IsFalse(bits[3]);
|
||||||
|
Assert.IsTrue(bits[4]);
|
||||||
|
Assert.IsFalse(bits[5]);
|
||||||
|
Assert.IsTrue(bits[6]);
|
||||||
|
Assert.IsTrue(bits[7]);
|
||||||
|
|
||||||
|
for (var index = 8; index < 32; index++)
|
||||||
|
{
|
||||||
|
Assert.IsFalse(bits[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
|
[TestMethod]
|
||||||
|
public void UnpackInternal_Ssse3_ShouldUnpackToSpanCorrectly()
|
||||||
|
{
|
||||||
|
if (!Ssse3.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int value = 0b11010100;
|
||||||
|
Span<bool> bits = stackalloc bool[32];
|
||||||
|
value.UnpackInternal_Ssse3(bits);
|
||||||
|
|
||||||
|
Assert.IsFalse(bits[0]);
|
||||||
|
Assert.IsFalse(bits[1]);
|
||||||
|
Assert.IsTrue(bits[2]);
|
||||||
|
Assert.IsFalse(bits[3]);
|
||||||
|
Assert.IsTrue(bits[4]);
|
||||||
|
Assert.IsFalse(bits[5]);
|
||||||
|
Assert.IsTrue(bits[6]);
|
||||||
|
Assert.IsTrue(bits[7]);
|
||||||
|
|
||||||
|
for (var index = 8; index < 32; index++)
|
||||||
|
{
|
||||||
|
Assert.IsFalse(bits[index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UnpackBits_ShouldThrow_GivenTooSmallSpan()
|
public void UnpackInternal_Avx2_ShouldUnpackToSpanCorrectly()
|
||||||
|
{
|
||||||
|
if (!Avx2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int value = 0b11010100;
|
||||||
|
Span<bool> bits = stackalloc bool[32];
|
||||||
|
value.UnpackInternal_Avx2(bits);
|
||||||
|
|
||||||
|
Assert.IsFalse(bits[0]);
|
||||||
|
Assert.IsFalse(bits[1]);
|
||||||
|
Assert.IsTrue(bits[2]);
|
||||||
|
Assert.IsFalse(bits[3]);
|
||||||
|
Assert.IsTrue(bits[4]);
|
||||||
|
Assert.IsFalse(bits[5]);
|
||||||
|
Assert.IsTrue(bits[6]);
|
||||||
|
Assert.IsTrue(bits[7]);
|
||||||
|
|
||||||
|
for (var index = 8; index < 32; index++)
|
||||||
|
{
|
||||||
|
Assert.IsFalse(bits[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Unpack_ShouldRepackEqually()
|
||||||
|
{
|
||||||
|
const int value = 0b11010100;
|
||||||
|
Assert.AreEqual(value, value.Unpack().PackInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Unpack_ShouldThrow_GivenTooSmallSpan()
|
||||||
{
|
{
|
||||||
Assert.ThrowsException<ArgumentException>(() =>
|
Assert.ThrowsException<ArgumentException>(() =>
|
||||||
{
|
{
|
||||||
|
const int value = 0b11010100;
|
||||||
Span<bool> bits = stackalloc bool[0];
|
Span<bool> bits = stackalloc bool[0];
|
||||||
0b11010100.Unpack(bits);
|
value.Unpack(bits);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,124 @@ public class ListTests
|
|||||||
Assert.ThrowsException<ArgumentNullException>(() => list!.Fill(0, 0, 0));
|
Assert.ThrowsException<ArgumentNullException>(() => list!.Fill(0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IndexOf_ShouldReturnCorrectValue_FromStartOfList()
|
||||||
|
{
|
||||||
|
int[] array = {0, 1, 2, 3, 4};
|
||||||
|
Assert.AreEqual(2, array.IndexOf(2));
|
||||||
|
Assert.AreEqual(2, array.IndexOf(2, 0));
|
||||||
|
Assert.AreEqual(2, array.IndexOf(2, 0, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IndexOf_ShouldReturnCorrectValue_GivenSubRange()
|
||||||
|
{
|
||||||
|
int[] array = {0, 1, 2, 3, 4, 0};
|
||||||
|
Assert.AreEqual(0, array.IndexOf(0));
|
||||||
|
Assert.AreEqual(0, array.IndexOf(0, 0));
|
||||||
|
Assert.AreEqual(0, array.IndexOf(0, 0, 5));
|
||||||
|
|
||||||
|
Assert.AreEqual(5, array.IndexOf(0, 1));
|
||||||
|
Assert.AreEqual(5, array.IndexOf(0, 1, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IndexOf_ShouldReturnNegative1_ForEmptyList()
|
||||||
|
{
|
||||||
|
int[] array = Array.Empty<int>();
|
||||||
|
Assert.AreEqual(-1, array.IndexOf(0));
|
||||||
|
Assert.AreEqual(-1, array.IndexOf(0, 0));
|
||||||
|
Assert.AreEqual(-1, array.IndexOf(0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IndexOf_ShouldThrowArgumentNullException_GivenNullList()
|
||||||
|
{
|
||||||
|
int[]? array = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array!.IndexOf(0));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array!.IndexOf(0, 0));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array!.IndexOf(0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IndexOf_ShouldThrowArgumentOutOfRangeException_GivenNegativeCount()
|
||||||
|
{
|
||||||
|
int[] array = Array.Empty<int>();
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => array.IndexOf(0, 0, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IndexOf_ShouldThrowArgumentOutOfRangeException_GivenNegativeStartIndex()
|
||||||
|
{
|
||||||
|
int[] array = Array.Empty<int>();
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => array.IndexOf(0, -1));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => array.IndexOf(0, -1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IndexOf_ShouldThrowArgumentOutOfRangeException_GivenInvalidStartIndexCountPair()
|
||||||
|
{
|
||||||
|
int[] array = {0, 1, 2};
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => array.IndexOf(0, 2, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Random_ShouldReturnContainedObject_GivenNotNull()
|
||||||
|
{
|
||||||
|
var list = new List<int>(Enumerable.Range(1, 52)); // 52! chance of being shuffled to the same order
|
||||||
|
int random = list.Random();
|
||||||
|
|
||||||
|
Assert.IsTrue(list.Contains(random));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Random_ShouldThrow_GivenNull()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((List<int>?)null)!.Random());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RemoveRange_ShouldThrowArgumentNullException_GivenNull()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((List<int>?)null)!.RemoveRange(new Range()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RemoveRange_ShouldThrowArgumentException_GivenEndIndexLessThanStart()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => new List<int>().RemoveRange(2..0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RemoveRange_ShouldThrowArgumentOutOfRangeException_GivenEndIndexGreaterThanOrEqualToCount()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => new List<int>().RemoveRange(..0));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => new List<int> {1}.RemoveRange(..2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RemoveRange_ShouldRemoveElements_GivenList()
|
||||||
|
{
|
||||||
|
var list = new List<int>
|
||||||
|
{
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
10
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.AreEqual(10, list.Count);
|
||||||
|
list.RemoveRange(2..5);
|
||||||
|
Assert.AreEqual(6, list.Count);
|
||||||
|
CollectionAssert.AreEqual(new[] {1, 2, 7, 8, 9, 10}, list);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Shuffle_ShouldReorder_GivenNotNull()
|
public void Shuffle_ShouldReorder_GivenNotNull()
|
||||||
{
|
{
|
||||||
@ -99,17 +217,107 @@ public class ListTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Random_ShouldReturnContainedObject_GivenNotNull()
|
public void Slice_ShouldReturnCorrectValue_GivenStartIndex()
|
||||||
{
|
{
|
||||||
var list = new List<int>(Enumerable.Range(1, 52)); // 52! chance of being shuffled to the same order
|
int[] array = {0, 1, 2, 3, 4, 5};
|
||||||
int random = list.Random();
|
CollectionAssert.AreEqual(new[] {2, 3, 4, 5}, array.Slice(2).ToArray());
|
||||||
|
|
||||||
Assert.IsTrue(list.Contains(random));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Random_ShouldThrow_GivenNull()
|
public void Slice_ShouldReturnCorrectValue_GivenStartIndexAndLength()
|
||||||
{
|
{
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => ((List<int>?)null)!.Random());
|
int[] array = {0, 1, 2, 3, 4, 5};
|
||||||
|
CollectionAssert.AreEqual(new[] {2, 3, 4}, array.Slice(2, 3).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Slice_ShouldReturnEmptyList_ForEmptyList()
|
||||||
|
{
|
||||||
|
int[] array = Array.Empty<int>();
|
||||||
|
CollectionAssert.AreEqual(Array.Empty<int>(), array.Slice(0).ToArray());
|
||||||
|
CollectionAssert.AreEqual(Array.Empty<int>(), array.Slice(0, 0).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Slice_ShouldThrowArgumentNullException_GivenNullList()
|
||||||
|
{
|
||||||
|
int[]? array = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array!.Slice(0));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array!.Slice(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Slice_ShouldThrowArgumentOutOfRangeException_GivenNegativeCount()
|
||||||
|
{
|
||||||
|
int[] array = Array.Empty<int>();
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => array.Slice(0, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Slice_ShouldThrowArgumentOutOfRangeException_GivenNegativeStartIndex()
|
||||||
|
{
|
||||||
|
int[] array = Array.Empty<int>();
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => array.Slice(-1));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => array.Slice(-1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Slice_ShouldThrowArgumentOutOfRangeException_GivenInvalidStartIndexCountPair()
|
||||||
|
{
|
||||||
|
int[] array = {0, 1, 2};
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => array.Slice(2, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Swap_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((IList<int>?)null)!.Swap(new List<int>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Swap_ShouldThrowArgumentNullException_GivenNullTarget()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => new List<int>().Swap(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Swap_ShouldSwapElements_GivenMatchingElementCount()
|
||||||
|
{
|
||||||
|
var first = new List<int> {1, 2, 3};
|
||||||
|
var second = new List<int> {4, 5, 6};
|
||||||
|
|
||||||
|
first.Swap(second);
|
||||||
|
|
||||||
|
CollectionAssert.AreEqual(new[] {4, 5, 6}, first, string.Join(' ', first));
|
||||||
|
CollectionAssert.AreEqual(new[] {1, 2, 3}, second, string.Join(' ', second));
|
||||||
|
|
||||||
|
first.Swap(second);
|
||||||
|
|
||||||
|
CollectionAssert.AreEqual(new[] {1, 2, 3}, first, string.Join(' ', first));
|
||||||
|
CollectionAssert.AreEqual(new[] {4, 5, 6}, second, string.Join(' ', second));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Swap_ShouldSwapElements_GivenDifferentElementCount()
|
||||||
|
{
|
||||||
|
var first = new List<int>
|
||||||
|
{
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5
|
||||||
|
};
|
||||||
|
var second = new List<int> {6, 7};
|
||||||
|
|
||||||
|
first.Swap(second);
|
||||||
|
|
||||||
|
CollectionAssert.AreEqual(new[] {6, 7}, first, string.Join(' ', first));
|
||||||
|
CollectionAssert.AreEqual(new[] {1, 2, 3, 4, 5}, second, string.Join(' ', second));
|
||||||
|
|
||||||
|
first.Swap(second);
|
||||||
|
|
||||||
|
CollectionAssert.AreEqual(new[] {1, 2, 3, 4, 5}, first, string.Join(' ', first));
|
||||||
|
CollectionAssert.AreEqual(new[] {6, 7}, second, string.Join(' ', second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
476
X10D.Tests/src/Collections/SpanTest.cs
Normal file
476
X10D.Tests/src/Collections/SpanTest.cs
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Collections;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class SpanTest
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Count_ShouldReturn0_GivenEmptySpan()
|
||||||
|
{
|
||||||
|
Span<int> span = Span<int>.Empty;
|
||||||
|
|
||||||
|
int count = span.Count(2);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Count_ShouldReturn0_GivenEmptyReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<int> span = ReadOnlySpan<int>.Empty;
|
||||||
|
|
||||||
|
int count = span.Count(2);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Count_ShouldReturn8_GivenSpanWith8MatchingElements()
|
||||||
|
{
|
||||||
|
Span<int> span = stackalloc int[16] {1, 2, 3, 2, 5, 2, 7, 2, 9, 2, 11, 2, 13, 2, 15, 2};
|
||||||
|
|
||||||
|
int count = span.Count(2);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Count_ShouldReturn8_GivenReadOnlySpanWith8MatchingElements()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<int> span = stackalloc int[16] {1, 2, 3, 2, 5, 2, 7, 2, 9, 2, 11, 2, 13, 2, 15, 2};
|
||||||
|
|
||||||
|
int count = span.Count(2);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnEmptySpan_ShouldYieldNothing_UsingCharDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = ReadOnlySpan<char>.Empty;
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> unused in span.Split(' '))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnEmptySpan_ShouldYieldNothing_UsingCharDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
Span<char> span = Span<char>.Empty;
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> unused in span.Split(' '))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnEmptySpan_ShouldYieldNothing_UsingStringDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = ReadOnlySpan<char>.Empty;
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> unused in span.Split(" "))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnEmptySpan_ShouldYieldNothing_UsingStringDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
Span<char> span = Span<char>.Empty;
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> unused in span.Split(" "))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnOneWord_ShouldYieldLength1_UsingCharDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = "Hello ".AsSpan();
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(' '))
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(1, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnOneWord_ShouldYieldLength1_UsingCharDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> source = "Hello ".AsSpan();
|
||||||
|
Span<char> span = stackalloc char[source.Length];
|
||||||
|
source.CopyTo(span);
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(' '))
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(1, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnOneWord_ShouldYieldLength1_UsingStringDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = "Hello ".AsSpan();
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(" "))
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(1, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnOneWord_ShouldYieldLength1_UsingStringDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> source = "Hello ".AsSpan();
|
||||||
|
Span<char> span = stackalloc char[source.Length];
|
||||||
|
source.CopyTo(span);
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(" "))
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(1, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnOneWordWithoutDelimiter_ShouldYieldLength1_UsingCharDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = "Hello".AsSpan();
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(' '))
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(1, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnOneWordWithoutDelimiter_ShouldYieldLength1_UsingCharDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> source = "Hello".AsSpan();
|
||||||
|
Span<char> span = stackalloc char[source.Length];
|
||||||
|
source.CopyTo(span);
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(' '))
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(1, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnOneWordWithoutDelimiter_ShouldYieldLength1_UsingStringDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = "Hello".AsSpan();
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(" "))
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(1, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnOneWordWithoutDelimiter_ShouldYieldLength1_UsingStringDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> source = "Hello".AsSpan();
|
||||||
|
Span<char> span = stackalloc char[source.Length];
|
||||||
|
source.CopyTo(span);
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(" "))
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(1, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnTwoWords_ShouldYieldLength2_UsingCharDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = "Hello World ".AsSpan();
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(' '))
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Assert.AreEqual("World", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(2, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnTwoWords_ShouldYieldLength2_UsingCharDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> source = "Hello World ".AsSpan();
|
||||||
|
Span<char> span = stackalloc char[source.Length];
|
||||||
|
source.CopyTo(span);
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(' '))
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Assert.AreEqual("World", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(2, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnTwoWords_ShouldYieldLength2_UsingStringDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = "Hello World ".AsSpan();
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(" "))
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Assert.AreEqual("World", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(2, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnTwoWords_ShouldYieldLength2_UsingStringDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> source = "Hello World ".AsSpan();
|
||||||
|
Span<char> span = stackalloc char[source.Length];
|
||||||
|
source.CopyTo(span);
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(" "))
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Assert.AreEqual("Hello", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Assert.AreEqual("World", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(2, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnThreeWords_ShouldYieldLength3_UsingCharDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = "Hello, the World ".AsSpan();
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(' '))
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Assert.AreEqual("Hello,", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Assert.AreEqual("the", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Assert.AreEqual("World", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(3, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnThreeWords_ShouldYieldLength3_UsingCharDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> source = "Hello, the World ".AsSpan();
|
||||||
|
Span<char> span = stackalloc char[source.Length];
|
||||||
|
source.CopyTo(span);
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(' '))
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Assert.AreEqual("Hello,", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Assert.AreEqual("the", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Assert.AreEqual("World", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(3, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnThreeWords_ShouldYieldLength3_UsingStringDelimiter_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> span = "Hello, the World ".AsSpan();
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(" "))
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Assert.AreEqual("Hello,", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Assert.AreEqual("the", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Assert.AreEqual("World", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(3, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Split_OnThreeWords_ShouldYieldLength3_UsingStringDelimiter_GivenSpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> source = "Hello, the World ".AsSpan();
|
||||||
|
Span<char> span = stackalloc char[source.Length];
|
||||||
|
source.CopyTo(span);
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (ReadOnlySpan<char> subSpan in span.Split(" "))
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Assert.AreEqual("Hello,", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Assert.AreEqual("the", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Assert.AreEqual("World", subSpan.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(3, index);
|
||||||
|
}
|
||||||
|
}
|
226
X10D.Tests/src/Core/IntrinsicTests.cs
Normal file
226
X10D.Tests/src/Core/IntrinsicTests.cs
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Core;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Core;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class IntrinsicTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void CorrectBoolean_ShouldReturnExpectedVector64Result_GivenInputVector()
|
||||||
|
{
|
||||||
|
var inputVector = Vector64.Create(0, 1, 2, 0, 3, 0, 0, (byte)4);
|
||||||
|
var expectedResult = Vector64.Create(0, 1, 1, 0, 1, 0, 0, (byte)1);
|
||||||
|
|
||||||
|
Vector64<byte> result = inputVector.CorrectBoolean();
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CorrectBooleanInternal_Fallback_ShouldReturnExpectedVector128Result_GivenInputVector()
|
||||||
|
{
|
||||||
|
var inputVector = Vector128.Create(0, 1, 2, 0, 3, 0, 0, 4, 5, 0, 0, 6, 0, 0, 7, (byte)8);
|
||||||
|
var expectedResult = Vector128.Create(0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, (byte)1);
|
||||||
|
|
||||||
|
Vector128<byte> result = inputVector.CorrectBooleanInternal_Fallback();
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CorrectBooleanInternal_Sse2_ShouldReturnExpectedVector128Result_GivenInputVector()
|
||||||
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputVector = Vector128.Create(0, 1, 2, 0, 3, 0, 0, 4, 5, 0, 0, 6, 0, 0, 7, (byte)8);
|
||||||
|
var expectedResult = Vector128.Create(0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, (byte)1);
|
||||||
|
|
||||||
|
Vector128<byte> result = inputVector.CorrectBooleanInternal_Sse2();
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CorrectBooleanInternal_Avx2_ShouldReturnExpectedVector256Result_GivenInputVector()
|
||||||
|
{
|
||||||
|
if (!Avx2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputVector = Vector256.Create(0, 1, 2, 0, 3, 0, 0, 4, 5, 0, 0, 6, 0, 0, 7, 8, 0, 1, 2, 0, 3, 0, 0, 4, 5, 0, 0, 6, 0,
|
||||||
|
0, 7, (byte)8);
|
||||||
|
var expectedResult = Vector256.Create(0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1,
|
||||||
|
0, 0, 1, (byte)1);
|
||||||
|
|
||||||
|
Vector256<byte> result = inputVector.CorrectBooleanInternal_Avx2();
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CorrectBooleanInternal_Fallback_ShouldReturnExpectedVector256Result_GivenInputVector()
|
||||||
|
{
|
||||||
|
var inputVector = Vector256.Create(0, 1, 2, 0, 3, 0, 0, 4, 5, 0, 0, 6, 0, 0, 7, 8, 0, 1, 2, 0, 3, 0, 0, 4, 5, 0, 0, 6, 0,
|
||||||
|
0, 7, (byte)8);
|
||||||
|
var expectedResult = Vector256.Create(0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1,
|
||||||
|
0, 0, 1, (byte)1);
|
||||||
|
|
||||||
|
Vector256<byte> result = inputVector.CorrectBooleanInternal_Fallback();
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void HorizontalOr_ShouldReturnCombinedVector_GivenInputVector128OfUInt32()
|
||||||
|
{
|
||||||
|
Vector128<uint> left = Vector128.Create(1U, 2U, 3U, 4U);
|
||||||
|
Vector128<uint> right = Vector128.Create(5U, 6U, 7U, 8U);
|
||||||
|
|
||||||
|
Vector128<uint> expected = Vector128.Create(3U, 7U, 7U, 15U);
|
||||||
|
Vector128<uint> actual = IntrinsicUtility.HorizontalOr(left, right);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void HorizontalOrInternal_Sse_ShouldReturnCombinedVector_GivenInputVector128OfInt32()
|
||||||
|
{
|
||||||
|
Vector128<int> left = Vector128.Create(1, 2, 3, 4);
|
||||||
|
Vector128<int> right = Vector128.Create(5, 6, 7, 8);
|
||||||
|
|
||||||
|
Vector128<int> expected = Vector128.Create(3, 7, 7, 15);
|
||||||
|
Vector128<int> actual = IntrinsicUtility.HorizontalOr_Sse(left, right);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void HorizontalOrInternal_Fallback_ShouldReturnCombinedVector_GivenInputVector128OfInt32()
|
||||||
|
{
|
||||||
|
Vector128<int> left = Vector128.Create(1, 2, 3, 4);
|
||||||
|
Vector128<int> right = Vector128.Create(5, 6, 7, 8);
|
||||||
|
|
||||||
|
Vector128<int> expected = Vector128.Create(3, 7, 7, 15);
|
||||||
|
Vector128<int> actual = IntrinsicUtility.HorizontalOrInternal_Fallback(left, right);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Multiply_ShouldReturnMultipliedVector_GivenInputVector128OfInt64()
|
||||||
|
{
|
||||||
|
Vector128<long> left = Vector128.Create(6L, 4L);
|
||||||
|
Vector128<long> right = Vector128.Create(2L, 3L);
|
||||||
|
|
||||||
|
Vector128<long> expected = Vector128.Create(12L, 12L);
|
||||||
|
Vector128<long> actual = IntrinsicUtility.Multiply(left, right);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MultiplyInternal_Sse2_ShouldReturnMultipliedVector_GivenInputVector128OfUInt64()
|
||||||
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector128<ulong> left = Vector128.Create(6UL, 4UL);
|
||||||
|
Vector128<ulong> right = Vector128.Create(2UL, 3UL);
|
||||||
|
|
||||||
|
Vector128<ulong> expected = Vector128.Create(12UL, 12UL);
|
||||||
|
Vector128<ulong> actual = IntrinsicUtility.MultiplyInternal_Sse2(left, right);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MultiplyInternal_Fallback_ShouldReturnMultipliedVector_GivenInputVector128OfUInt64()
|
||||||
|
{
|
||||||
|
Vector128<ulong> left = Vector128.Create(6UL, 4UL);
|
||||||
|
Vector128<ulong> right = Vector128.Create(2UL, 3UL);
|
||||||
|
|
||||||
|
Vector128<ulong> expected = Vector128.Create(12UL, 12UL);
|
||||||
|
Vector128<ulong> actual = IntrinsicUtility.MultiplyInternal_Fallback(left, right);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Multiply_ShouldReturnMultipliedVector_GivenInputVector256OfInt64()
|
||||||
|
{
|
||||||
|
Vector256<long> left = Vector256.Create(4L, 6L, 8L, 10L);
|
||||||
|
Vector256<long> right = Vector256.Create(2L, 3L, 4L, 5L);
|
||||||
|
|
||||||
|
Vector256<long> expected = Vector256.Create(8L, 18L, 32L, 50L);
|
||||||
|
Vector256<long> actual = IntrinsicUtility.Multiply(left, right);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MultiplyInternal_Avx2_ShouldReturnMultipliedVector_GivenInputVector256OfUInt64()
|
||||||
|
{
|
||||||
|
if (!Avx2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector256<ulong> left = Vector256.Create(4UL, 6UL, 8UL, 10UL);
|
||||||
|
Vector256<ulong> right = Vector256.Create(2UL, 3UL, 4UL, 5UL);
|
||||||
|
|
||||||
|
Vector256<ulong> expected = Vector256.Create(8UL, 18UL, 32UL, 50UL);
|
||||||
|
Vector256<ulong> actual = IntrinsicUtility.MultiplyInternal_Avx2(left, right);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MultiplyInternal_Fallback_ShouldReturnMultipliedVector_GivenInputVector256OfUInt64()
|
||||||
|
{
|
||||||
|
Vector256<ulong> left = Vector256.Create(4UL, 6UL, 8UL, 10UL);
|
||||||
|
Vector256<ulong> right = Vector256.Create(2UL, 3UL, 4UL, 5UL);
|
||||||
|
|
||||||
|
Vector256<ulong> expected = Vector256.Create(8UL, 18UL, 32UL, 50UL);
|
||||||
|
Vector256<ulong> actual = IntrinsicUtility.MultiplyInternal_Fallback(left, right);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReverseElementsInternal_Fallback_ShouldReturnExpectedVector128Result_GivenInputVector()
|
||||||
|
{
|
||||||
|
var inputVector = Vector128.Create(42UL, 69UL);
|
||||||
|
var expectedResult = Vector128.Create(69UL, 42UL);
|
||||||
|
|
||||||
|
Vector128<ulong> result = inputVector.ReverseElementsInternal_Fallback();
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReverseElementsInternal_Sse2_ShouldReturnExpectedVector128Result_GivenInputVector()
|
||||||
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputVector = Vector128.Create(42UL, 69UL);
|
||||||
|
var expectedResult = Vector128.Create(69UL, 42UL);
|
||||||
|
|
||||||
|
Vector128<ulong> result = inputVector.ReverseElementsInternal_Sse2();
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedResult, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
24
X10D.Tests/src/Core/NullableTests.cs
Normal file
24
X10D.Tests/src/Core/NullableTests.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Core;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Core;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class NullableTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void TryGetValue_ShouldBeTrue_GivenValue()
|
||||||
|
{
|
||||||
|
int? value = 42;
|
||||||
|
Assert.IsTrue(value.TryGetValue(out int returnedValue));
|
||||||
|
Assert.AreEqual(value, returnedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TryGetValue_ShouldBeFalse_GivenNull()
|
||||||
|
{
|
||||||
|
int? value = null;
|
||||||
|
Assert.IsFalse(value.TryGetValue(out int returnedValue));
|
||||||
|
Assert.AreEqual(default, returnedValue);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Collections;
|
||||||
using X10D.Core;
|
using X10D.Core;
|
||||||
|
|
||||||
namespace X10D.Tests.Core;
|
namespace X10D.Tests.Core;
|
||||||
@ -126,6 +127,48 @@ public class RandomTests
|
|||||||
Assert.AreEqual(0, random.NextFrom(Source()));
|
Assert.AreEqual(0, random.NextFrom(Source()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void NextFromSpan_ShouldThrow_GivenNullRandom()
|
||||||
|
{
|
||||||
|
Random? random = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() =>
|
||||||
|
{
|
||||||
|
Span<int> span = stackalloc int[1];
|
||||||
|
return random!.NextFrom(span);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void NextFromReadOnlySpan_ShouldThrow_GivenNullRandom()
|
||||||
|
{
|
||||||
|
Random? random = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() =>
|
||||||
|
{
|
||||||
|
Span<int> span = stackalloc int[1];
|
||||||
|
return random!.NextFrom(span.AsReadOnly());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void NextFromSpan_ShouldReturnOnlyValue_GivenSpanWithLength1()
|
||||||
|
{
|
||||||
|
Span<int> span = stackalloc int[1];
|
||||||
|
span[0] = 42;
|
||||||
|
|
||||||
|
var random = new Random(1234);
|
||||||
|
Assert.AreEqual(42, random.NextFrom(span));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void NextFromReadOnlySpan_ShouldReturnOnlyValue_GivenSpanWithLength1()
|
||||||
|
{
|
||||||
|
Span<int> span = stackalloc int[1];
|
||||||
|
span[0] = 42;
|
||||||
|
|
||||||
|
var random = new Random(1234);
|
||||||
|
Assert.AreEqual(42, random.NextFrom(span.AsReadOnly()));
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void NextInt16_ShouldBe13076_GivenSeed1234()
|
public void NextInt16_ShouldBe13076_GivenSeed1234()
|
||||||
{
|
{
|
||||||
@ -183,6 +226,9 @@ public class RandomTests
|
|||||||
Random? random = null;
|
Random? random = null;
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => random!.NextSingle(10));
|
Assert.ThrowsException<ArgumentNullException>(() => random!.NextSingle(10));
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => random!.NextSingle(0, 10));
|
Assert.ThrowsException<ArgumentNullException>(() => random!.NextSingle(0, 10));
|
||||||
|
#if !NET6_0_OR_GREATER
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => random!.NextSingle());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
570
X10D.Tests/src/Core/SpanTest.cs
Normal file
570
X10D.Tests/src/Core/SpanTest.cs
Normal file
@ -0,0 +1,570 @@
|
|||||||
|
#if NET5_0_OR_GREATER
|
||||||
|
using System.Runtime.Intrinsics.Arm;
|
||||||
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
#endif
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Core;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Core;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class SpanTest
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnFalse_GivenReadOnlySpanWithNoMatchingElements_UsingByteEnum()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<EnumByte> span = stackalloc EnumByte[1] {EnumByte.B};
|
||||||
|
|
||||||
|
Assert.IsFalse(span.Contains(EnumByte.A));
|
||||||
|
Assert.IsFalse(span.Contains(EnumByte.C));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnFalse_GivenReadOnlySpanWithNoMatchingElements_UsingInt16Enum()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<EnumInt16> span = stackalloc EnumInt16[1] {EnumInt16.B};
|
||||||
|
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt16.A));
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt16.C));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnFalse_GivenReadOnlySpanWithNoMatchingElements_UsingInt32Enum()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<EnumInt32> span = stackalloc EnumInt32[1] {EnumInt32.B};
|
||||||
|
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt32.A));
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt32.C));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnFalse_GivenReadOnlySpanWithNoMatchingElements_UsingInt64Enum()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<EnumInt64> span = stackalloc EnumInt64[1] {EnumInt64.B};
|
||||||
|
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt64.A));
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt64.C));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnTrue_GivenReadOnlySpanWithMatchingElements_UsingByteEnum()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<EnumByte> span = stackalloc EnumByte[1] {EnumByte.B};
|
||||||
|
|
||||||
|
Assert.IsTrue(span.Contains(EnumByte.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnTrue_GivenReadOnlySpanWithMatchingElements_UsingInt16Enum()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<EnumInt16> span = stackalloc EnumInt16[1] {EnumInt16.B};
|
||||||
|
|
||||||
|
Assert.IsTrue(span.Contains(EnumInt16.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnTrue_GivenReadOnlySpanWithMatchingElements_UsingInt32Enum()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<EnumInt32> span = stackalloc EnumInt32[1] {EnumInt32.B};
|
||||||
|
|
||||||
|
Assert.IsTrue(span.Contains(EnumInt32.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnTrue_GivenReadOnlySpanWithMatchingElements_UsingInt64Enum()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<EnumInt64> span = stackalloc EnumInt64[1] {EnumInt64.B};
|
||||||
|
|
||||||
|
Assert.IsTrue(span.Contains(EnumInt64.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnFalse_GivenSpanWithNoMatchingElements_UsingByteEnum()
|
||||||
|
{
|
||||||
|
Span<EnumByte> span = stackalloc EnumByte[1] {EnumByte.B};
|
||||||
|
|
||||||
|
Assert.IsFalse(span.Contains(EnumByte.A));
|
||||||
|
Assert.IsFalse(span.Contains(EnumByte.C));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnFalse_GivenSpanWithNoMatchingElements_UsingInt16Enum()
|
||||||
|
{
|
||||||
|
Span<EnumInt16> span = stackalloc EnumInt16[1] {EnumInt16.B};
|
||||||
|
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt16.A));
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt16.C));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnFalse_GivenSpanWithNoMatchingElements_UsingInt32Enum()
|
||||||
|
{
|
||||||
|
Span<EnumInt32> span = stackalloc EnumInt32[1] {EnumInt32.B};
|
||||||
|
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt32.A));
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt32.C));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnFalse_GivenSpanWithNoMatchingElements_UsingInt64Enum()
|
||||||
|
{
|
||||||
|
Span<EnumInt64> span = stackalloc EnumInt64[1] {EnumInt64.B};
|
||||||
|
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt64.A));
|
||||||
|
Assert.IsFalse(span.Contains(EnumInt64.C));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnTrue_GivenSpanWithMatchingElements_UsingByteEnum()
|
||||||
|
{
|
||||||
|
Span<EnumByte> span = stackalloc EnumByte[1] {EnumByte.B};
|
||||||
|
|
||||||
|
Assert.IsTrue(span.Contains(EnumByte.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnTrue_GivenSpanWithMatchingElements_UsingInt16Enum()
|
||||||
|
{
|
||||||
|
Span<EnumInt16> span = stackalloc EnumInt16[1] {EnumInt16.B};
|
||||||
|
|
||||||
|
Assert.IsTrue(span.Contains(EnumInt16.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnTrue_GivenSpanWithMatchingElements_UsingInt32Enum()
|
||||||
|
{
|
||||||
|
Span<EnumInt32> span = stackalloc EnumInt32[1] {EnumInt32.B};
|
||||||
|
|
||||||
|
Assert.IsTrue(span.Contains(EnumInt32.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Contains_ShouldReturnTrue_GivenSpanWithMatchingElements_UsingInt64Enum()
|
||||||
|
{
|
||||||
|
Span<EnumInt64> span = stackalloc EnumInt64[1] {EnumInt64.B};
|
||||||
|
|
||||||
|
Assert.IsTrue(span.Contains(EnumInt64.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackByte_ShouldThrowArgumentException_GivenSpanLengthGreaterThan8()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() =>
|
||||||
|
{
|
||||||
|
Span<bool> span = stackalloc bool[9];
|
||||||
|
return span.PackByte();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt16_ShouldThrowArgumentException_GivenSpanLengthGreaterThan16()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() =>
|
||||||
|
{
|
||||||
|
Span<bool> span = stackalloc bool[17];
|
||||||
|
return span.PackInt16();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt32_ShouldThrowArgumentException_GivenSpanLengthGreaterThan32()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() =>
|
||||||
|
{
|
||||||
|
Span<bool> span = stackalloc bool[33];
|
||||||
|
return span.PackInt32();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldThrowArgumentException_GivenSpanLengthGreaterThan64()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() =>
|
||||||
|
{
|
||||||
|
Span<bool> span = stackalloc bool[65];
|
||||||
|
return span.PackInt64();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackByteInternal_Fallback_ShouldReturnCorrectByte_GivenReadOnlySpan_Using()
|
||||||
|
{
|
||||||
|
const byte expected = 0b00110011;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[8] {true, true, false, false, true, true, false, false};
|
||||||
|
|
||||||
|
byte actual = span.PackByteInternal_Fallback();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
|
[TestMethod]
|
||||||
|
public void PackByteInternal_Sse2_ShouldReturnCorrectByte_GivenReadOnlySpan_Using()
|
||||||
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte expected = 0b00110011;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[8] {true, true, false, false, true, true, false, false};
|
||||||
|
|
||||||
|
byte actual = span.PackByteInternal_Sse2();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackByteInternal_AdvSimd_ShouldReturnCorrectByte_GivenReadOnlySpan_Using()
|
||||||
|
{
|
||||||
|
if (!AdvSimd.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte expected = 0b00110011;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[8] {true, true, false, false, true, true, false, false};
|
||||||
|
|
||||||
|
byte actual = span.PackByteInternal_AdvSimd();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt16_ShouldReturnSameAsPackByte_WhenSpanHasLength8()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[8] {true, true, false, false, true, true, false, false};
|
||||||
|
|
||||||
|
short expected = span.PackByte();
|
||||||
|
short actual = span.PackInt16();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt16Internal_Fallback_ShouldReturnCorrectInt16_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
const short expected = 0b00101101_11010100;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[16]
|
||||||
|
{
|
||||||
|
false, false, true, false, true, false, true, true, true, false, true, true, false, true, false, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
short actual = span.PackInt16Internal_Fallback();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt16Internal_Sse2_ShouldReturnCorrectInt16_GivenReadOnlySpan_Using()
|
||||||
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const short expected = 0b00101101_11010100;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[16]
|
||||||
|
{
|
||||||
|
false, false, true, false, true, false, true, true, true, false, true, true, false, true, false, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
short actual = span.PackInt16Internal_Sse2();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt32Internal_Fallback_ShouldReturnCorrectInt32_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
const int expected = 0b01010101_10101010_01010101_10101010;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[32]
|
||||||
|
{
|
||||||
|
false, true, false, true, false, true, false, true, true, false, true, false, true, false, true, false, false,
|
||||||
|
true, false, true, false, true, false, true, true, false, true, false, true, false, true, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
int actual = span.PackInt32Internal_Fallback();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt32Internal_Sse2_ShouldReturnCorrectInt32_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int expected = 0b01010101_10101010_01010101_10101010;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[32]
|
||||||
|
{
|
||||||
|
false, true, false, true, false, true, false, true, true, false, true, false, true, false, true, false, false,
|
||||||
|
true, false, true, false, true, false, true, true, false, true, false, true, false, true, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
int actual = span.PackInt32Internal_Sse2();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt32Internal_Avx2_ShouldReturnCorrectInt32_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
if (!Avx2.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int expected = 0b01010101_10101010_01010101_10101010;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[32]
|
||||||
|
{
|
||||||
|
false, true, false, true, false, true, false, true, true, false, true, false, true, false, true, false, false,
|
||||||
|
true, false, true, false, true, false, true, true, false, true, false, true, false, true, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
int actual = span.PackInt32Internal_Avx2();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt32Internal_AdvSimd_ShouldReturnCorrectInt32_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
if (!AdvSimd.IsSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int expected = 0b01010101_10101010_01010101_10101010;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[32]
|
||||||
|
{
|
||||||
|
false, true, false, true, false, true, false, true, true, false, true, false, true, false, true, false, false,
|
||||||
|
true, false, true, false, true, false, true, true, false, true, false, true, false, true, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
int actual = span.PackInt32Internal_AdvSimd();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt32_ShouldReturnSameAsPackByte_WhenSpanHasLength8_UsingReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[8] {true, true, false, false, true, true, false, false};
|
||||||
|
|
||||||
|
int expected = span.PackByte();
|
||||||
|
int actual = span.PackInt32();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt32_ShouldReturnSameAsPackByte_WhenSpanHasLength8_UsingSpan()
|
||||||
|
{
|
||||||
|
Span<bool> span = stackalloc bool[8] {true, true, false, false, true, true, false, false};
|
||||||
|
|
||||||
|
int expected = span.PackByte();
|
||||||
|
int actual = span.PackInt32();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt32_ShouldReturnSameAsPackInt16_WhenSpanHasLength16_UsingReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[16]
|
||||||
|
{
|
||||||
|
false, false, true, false, true, false, true, true, true, false, true, true, false, true, false, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
int expected = span.PackInt16();
|
||||||
|
int actual = span.PackInt32();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt32_ShouldReturnSameAsPackInt16_WhenSpanHasLength16_UsingSpan()
|
||||||
|
{
|
||||||
|
Span<bool> span = stackalloc bool[16]
|
||||||
|
{
|
||||||
|
false, false, true, false, true, false, true, true, true, false, true, true, false, true, false, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
int expected = span.PackInt16();
|
||||||
|
int actual = span.PackInt32();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldReturnCorrectInt64_GivenReadOnlySpan()
|
||||||
|
{
|
||||||
|
const long expected = 0b01010101_11010110_01101001_11010110_00010010_10010111_00101100_10100101;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[64]
|
||||||
|
{
|
||||||
|
true, false, true, false, false, true, false, true, false, false, true, true, false, true, false, false, true,
|
||||||
|
true, true, false, true, false, false, true, false, true, false, false, true, false, false, false, false, true,
|
||||||
|
true, false, true, false, true, true, true, false, false, true, false, true, true, false, false, true, true,
|
||||||
|
false, true, false, true, true, true, false, true, false, true, false, true, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldReturnCorrectInt64_GivenSpan()
|
||||||
|
{
|
||||||
|
const long expected = 0b01010101_11010110_01101001_11010110_00010010_10010111_00101100_10100101;
|
||||||
|
Span<bool> span = stackalloc bool[64]
|
||||||
|
{
|
||||||
|
true, false, true, false, false, true, false, true, false, false, true, true, false, true, false, false, true,
|
||||||
|
true, true, false, true, false, false, true, false, true, false, false, true, false, false, false, false, true,
|
||||||
|
true, false, true, false, true, true, true, false, false, true, false, true, true, false, false, true, true,
|
||||||
|
false, true, false, true, true, true, false, true, false, true, false, true, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldReturnSameAsPackByte_WhenSpanHasLength8_UsingReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[8] {true, true, false, false, true, true, false, false};
|
||||||
|
|
||||||
|
long expected = span.PackByte();
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldReturnSameAsPackByte_WhenSpanHasLength8_UsingSpan()
|
||||||
|
{
|
||||||
|
Span<bool> span = stackalloc bool[8] {true, true, false, false, true, true, false, false};
|
||||||
|
|
||||||
|
long expected = span.PackByte();
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldReturnSameAsPackInt16_WhenSpanHasLength16_UsingReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[16]
|
||||||
|
{
|
||||||
|
false, false, true, false, true, false, true, true, true, false, true, true, false, true, false, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
long expected = span.PackInt16();
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldReturnSameAsPackInt16_WhenSpanHasLength16_UsingSpan()
|
||||||
|
{
|
||||||
|
Span<bool> span = stackalloc bool[16]
|
||||||
|
{
|
||||||
|
false, false, true, false, true, false, true, true, true, false, true, true, false, true, false, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
long expected = span.PackInt16();
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldReturnSameAsPackInt32_WhenSpanHasLength16_UsingReadOnlySpan()
|
||||||
|
{
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[32]
|
||||||
|
{
|
||||||
|
false, true, false, true, false, true, false, true, true, false, true, false, true, false, true, false, false,
|
||||||
|
true, false, true, false, true, false, true, true, false, true, false, true, false, true, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
long expected = span.PackInt32();
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldReturnSameAsPackInt32_WhenSpanHasLength16_UsingSpan()
|
||||||
|
{
|
||||||
|
Span<bool> span = stackalloc bool[32]
|
||||||
|
{
|
||||||
|
false, true, false, true, false, true, false, true, true, false, true, false, true, false, true, false, false,
|
||||||
|
true, false, true, false, true, false, true, true, false, true, false, true, false, true, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
long expected = span.PackInt32();
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldFallbackAndReturnCorrectValue_GivenNonPowerOfTwoLength_UsingReadOnlySpan()
|
||||||
|
{
|
||||||
|
const long expected = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000001_01010011;
|
||||||
|
ReadOnlySpan<bool> span = stackalloc bool[10] {true, true, false, false, true, false, true, false, true, false};
|
||||||
|
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PackInt64_ShouldFallbackAndReturnCorrectValue_GivenNonPowerOfTwoLength_UsingSpan()
|
||||||
|
{
|
||||||
|
const long expected = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000001_01010011;
|
||||||
|
Span<bool> span = stackalloc bool[10] {true, true, false, false, true, false, true, false, true, false};
|
||||||
|
|
||||||
|
long actual = span.PackInt64();
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum EnumByte : byte
|
||||||
|
{
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum EnumInt16 : short
|
||||||
|
{
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum EnumInt32
|
||||||
|
{
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum EnumInt64 : long
|
||||||
|
{
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C
|
||||||
|
}
|
||||||
|
}
|
167
X10D.Tests/src/Drawing/CircleFTests.cs
Normal file
167
X10D.Tests/src/Drawing/CircleFTests.cs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class CircleFTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Area_ShouldBePiRadiusRadius_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
var unitCircle = CircleF.Unit;
|
||||||
|
Assert.AreEqual(MathF.PI, unitCircle.Area);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Circumference_ShouldBe2PiRadius_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
var unitCircle = CircleF.Unit;
|
||||||
|
Assert.AreEqual(2 * MathF.PI, unitCircle.Circumference, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenUnitCircleAndEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, CircleF.Empty.CompareTo(CircleF.Unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenUnitCircleAndEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, CircleF.Unit.CompareTo(CircleF.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenEmptyCircleAndUnitCircleAsObject()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, CircleF.Empty.CompareTo((object)CircleF.Unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenNull()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, CircleF.Unit.CompareTo(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeZero_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
var unitCircle = CircleF.Unit;
|
||||||
|
Assert.AreEqual(0, unitCircle.CompareTo(unitCircle));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldThrowArgumentException_GivenInvalidType()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => CircleF.Unit.CompareTo(new object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Diameter_ShouldBe2_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(2.0f, CircleF.Unit.Diameter, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoUnitCircles()
|
||||||
|
{
|
||||||
|
var unitCircle1 = CircleF.Unit;
|
||||||
|
var unitCircle2 = CircleF.Unit;
|
||||||
|
Assert.AreEqual(unitCircle1, unitCircle2);
|
||||||
|
Assert.IsTrue(unitCircle1 == unitCircle2);
|
||||||
|
Assert.IsFalse(unitCircle1 != unitCircle2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenUnitCirclesAsObjects()
|
||||||
|
{
|
||||||
|
CircleF unitCircle1 = CircleF.Unit;
|
||||||
|
object unitCircle2 = CircleF.Unit;
|
||||||
|
Assert.AreEqual(unitCircle1, unitCircle2);
|
||||||
|
Assert.IsTrue(unitCircle1.Equals(unitCircle2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentCircles()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual(CircleF.Unit, CircleF.Empty);
|
||||||
|
Assert.IsFalse(CircleF.Unit == CircleF.Empty);
|
||||||
|
Assert.IsTrue(CircleF.Unit != CircleF.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentObjects()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual((object?)null, CircleF.Empty);
|
||||||
|
Assert.IsFalse(CircleF.Empty.Equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = CircleF.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, CircleF.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = CircleF.Unit.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, CircleF.Unit.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Explicit_ShouldReturnEquivalentCircle_GivenCircle()
|
||||||
|
{
|
||||||
|
CircleF unitCircle = CircleF.Unit;
|
||||||
|
Circle converted = (Circle)unitCircle;
|
||||||
|
|
||||||
|
Assert.AreEqual(unitCircle, converted);
|
||||||
|
Assert.AreEqual(unitCircle.Radius, converted.Radius);
|
||||||
|
Assert.AreEqual(unitCircle.Center, converted.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_GreaterThan_True_GivenUnitAndEmptyCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(CircleF.Unit > CircleF.Empty);
|
||||||
|
Assert.IsTrue(CircleF.Unit >= CircleF.Empty);
|
||||||
|
Assert.IsFalse(CircleF.Unit < CircleF.Empty);
|
||||||
|
Assert.IsFalse(CircleF.Unit <= CircleF.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentCircle_GivenCircle()
|
||||||
|
{
|
||||||
|
Circle unitCircle = Circle.Unit;
|
||||||
|
CircleF converted = unitCircle;
|
||||||
|
|
||||||
|
Assert.AreEqual(unitCircle, converted);
|
||||||
|
Assert.AreEqual(unitCircle.Radius, converted.Radius);
|
||||||
|
Assert.AreEqual(unitCircle.Center, converted.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_LessThan_True_GivenEmptyAndUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(CircleF.Empty < CircleF.Unit);
|
||||||
|
Assert.IsTrue(CircleF.Empty <= CircleF.Unit);
|
||||||
|
Assert.IsFalse(CircleF.Empty > CircleF.Unit);
|
||||||
|
Assert.IsFalse(CircleF.Empty >= CircleF.Unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Radius_ShouldBe0_GivenEmptyCircle()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0.0f, CircleF.Empty.Radius, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Radius_ShouldBe1_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1.0f, CircleF.Unit.Radius, 1e-6f);
|
||||||
|
}
|
||||||
|
}
|
145
X10D.Tests/src/Drawing/CircleTests.cs
Normal file
145
X10D.Tests/src/Drawing/CircleTests.cs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class CircleTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Area_ShouldBePiRadiusRadius_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
var unitCircle = Circle.Unit;
|
||||||
|
Assert.AreEqual(MathF.PI * unitCircle.Radius * unitCircle.Radius, unitCircle.Area);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Circumference_ShouldBe2PiRadius_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
var unitCircle = Circle.Unit;
|
||||||
|
Assert.AreEqual(2.0f * MathF.PI * unitCircle.Radius, unitCircle.Circumference, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenUnitCircleAndEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, Circle.Empty.CompareTo(Circle.Unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenUnitCircleAndEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Circle.Unit.CompareTo(Circle.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenEmptyCircleAndUnitCircleAsObject()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, Circle.Empty.CompareTo((object)Circle.Unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenNull()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Circle.Unit.CompareTo(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeZero_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
var unitCircle = Circle.Unit;
|
||||||
|
Assert.AreEqual(0, unitCircle.CompareTo(unitCircle));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldThrowArgumentException_GivenInvalidType()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => Circle.Unit.CompareTo(new object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Diameter_ShouldBe2_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(2.0f, Circle.Unit.Diameter, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoUnitCircles()
|
||||||
|
{
|
||||||
|
var unitCircle1 = Circle.Unit;
|
||||||
|
var unitCircle2 = Circle.Unit;
|
||||||
|
Assert.AreEqual(unitCircle1, unitCircle2);
|
||||||
|
Assert.IsTrue(unitCircle1 == unitCircle2);
|
||||||
|
Assert.IsFalse(unitCircle1 != unitCircle2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenUnitCirclesAsObjects()
|
||||||
|
{
|
||||||
|
Circle unitCircle1 = Circle.Unit;
|
||||||
|
object unitCircle2 = Circle.Unit;
|
||||||
|
Assert.AreEqual(unitCircle1, unitCircle2);
|
||||||
|
Assert.IsTrue(unitCircle1.Equals(unitCircle2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentCircles()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual(Circle.Unit, Circle.Empty);
|
||||||
|
Assert.IsFalse(Circle.Unit == Circle.Empty);
|
||||||
|
Assert.IsTrue(Circle.Unit != Circle.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentObjects()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual((object?)null, Circle.Empty);
|
||||||
|
Assert.IsFalse(Circle.Empty.Equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Circle.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Circle.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Circle.Unit.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Circle.Unit.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_GreaterThan_True_GivenUnitAndEmptyCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Circle.Unit > Circle.Empty);
|
||||||
|
Assert.IsTrue(Circle.Unit >= Circle.Empty);
|
||||||
|
Assert.IsFalse(Circle.Unit < Circle.Empty);
|
||||||
|
Assert.IsFalse(Circle.Unit <= Circle.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_LessThan_True_GivenEmptyAndUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Circle.Empty < Circle.Unit);
|
||||||
|
Assert.IsTrue(Circle.Empty <= Circle.Unit);
|
||||||
|
Assert.IsFalse(Circle.Empty > Circle.Unit);
|
||||||
|
Assert.IsFalse(Circle.Empty >= Circle.Unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Radius_ShouldBe0_GivenEmptyCircle()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, Circle.Empty.Radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Radius_ShouldBe1_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Circle.Unit.Radius);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,203 @@ public class ColorTests
|
|||||||
private static readonly Color Magenta = Color.FromArgb(255, 0, 255);
|
private static readonly Color Magenta = Color.FromArgb(255, 0, 255);
|
||||||
private static readonly Color Yellow = Color.FromArgb(255, 255, 0);
|
private static readonly Color Yellow = Color.FromArgb(255, 255, 0);
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Deconstruct_ShouldDeconstructColor_GivenColor()
|
||||||
|
{
|
||||||
|
(byte r, byte g, byte b) = Black;
|
||||||
|
Assert.AreEqual(0, r);
|
||||||
|
Assert.AreEqual(0, g);
|
||||||
|
Assert.AreEqual(0, b);
|
||||||
|
|
||||||
|
(byte a, r, g, b) = Black;
|
||||||
|
Assert.AreEqual(255, a);
|
||||||
|
Assert.AreEqual(0, r);
|
||||||
|
Assert.AreEqual(0, g);
|
||||||
|
Assert.AreEqual(0, b);
|
||||||
|
|
||||||
|
(r, g, b) = Red;
|
||||||
|
Assert.AreEqual(255, r);
|
||||||
|
Assert.AreEqual(0, g);
|
||||||
|
Assert.AreEqual(0, b);
|
||||||
|
|
||||||
|
(a, r, g, b) = Red;
|
||||||
|
Assert.AreEqual(255, a);
|
||||||
|
Assert.AreEqual(255, r);
|
||||||
|
Assert.AreEqual(0, g);
|
||||||
|
Assert.AreEqual(0, b);
|
||||||
|
|
||||||
|
(r, g, b) = Green;
|
||||||
|
Assert.AreEqual(0, r);
|
||||||
|
Assert.AreEqual(255, g);
|
||||||
|
Assert.AreEqual(0, b);
|
||||||
|
|
||||||
|
(a, r, g, b) = Green;
|
||||||
|
Assert.AreEqual(255, a);
|
||||||
|
Assert.AreEqual(0, r);
|
||||||
|
Assert.AreEqual(255, g);
|
||||||
|
Assert.AreEqual(0, b);
|
||||||
|
|
||||||
|
(r, g, b) = Blue;
|
||||||
|
Assert.AreEqual(0, r);
|
||||||
|
Assert.AreEqual(0, g);
|
||||||
|
Assert.AreEqual(255, b);
|
||||||
|
|
||||||
|
(a, r, g, b) = Blue;
|
||||||
|
Assert.AreEqual(255, a);
|
||||||
|
Assert.AreEqual(0, r);
|
||||||
|
Assert.AreEqual(0, g);
|
||||||
|
Assert.AreEqual(255, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetClosestConsoleColor_ShouldReturnClosestColor_GivenValidColor()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Transparent.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.AliceBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.AntiqueWhite.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Cyan, Color.Aqua.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.Aquamarine.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Azure.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Beige.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Bisque.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Black, Color.Black.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.BlanchedAlmond.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Blue, Color.Blue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkMagenta, Color.BlueViolet.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkRed, Color.Brown.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.BurlyWood.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.CadetBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Yellow, Color.Chartreuse.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkYellow, Color.Chocolate.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkYellow, Color.Coral.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.CornflowerBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Cornsilk.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Red, Color.Crimson.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Cyan, Color.Cyan.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkBlue, Color.DarkBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkCyan, Color.DarkCyan.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkYellow, Color.DarkGoldenrod.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.DarkGray.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGreen, Color.DarkGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.DarkKhaki.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkMagenta, Color.DarkMagenta.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.DarkOliveGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkYellow, Color.DarkOrange.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkMagenta, Color.DarkOrchid.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkRed, Color.DarkRed.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.DarkSalmon.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.DarkSeaGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.DarkSlateBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGreen, Color.DarkSlateGray.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Cyan, Color.DarkTurquoise.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkMagenta, Color.DarkViolet.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Magenta, Color.DeepPink.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Cyan, Color.DeepSkyBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.DimGray.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Cyan, Color.DodgerBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkRed, Color.Firebrick.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.FloralWhite.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Green, Color.ForestGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Magenta, Color.Fuchsia.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Gainsboro.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.GhostWhite.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Yellow, Color.Gold.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkYellow, Color.Goldenrod.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.Gray.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Green, Color.Green.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Yellow, Color.GreenYellow.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Honeydew.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.HotPink.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.IndianRed.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkMagenta, Color.Indigo.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Ivory.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.Khaki.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Lavender.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.LavenderBlush.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Yellow, Color.LawnGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.LemonChiffon.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.LightBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.LightCoral.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.LightCyan.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.LightGoldenrodYellow.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.LightGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.LightGray.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.LightPink.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.LightSalmon.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkCyan, Color.LightSeaGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.LightSkyBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.LightSlateGray.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.LightSteelBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.LightYellow.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Green, Color.Lime.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Green, Color.LimeGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Linen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Magenta, Color.Magenta.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkRed, Color.Maroon.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.MediumAquamarine.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Blue, Color.MediumBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.MediumOrchid.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.MediumPurple.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkCyan, Color.MediumSeaGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.MediumSlateBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Cyan, Color.MediumSpringGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Cyan, Color.MediumTurquoise.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkMagenta, Color.MediumVioletRed.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkBlue, Color.MidnightBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.MintCream.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.MistyRose.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Moccasin.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.NavajoWhite.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkBlue, Color.Navy.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.OldLace.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.Olive.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.OliveDrab.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkYellow, Color.Orange.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Red, Color.OrangeRed.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.Orchid.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.PaleGoldenrod.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.PaleGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.PaleTurquoise.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.PaleVioletRed.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.PapayaWhip.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.PeachPuff.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkYellow, Color.Peru.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Pink.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.Plum.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.PowderBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkMagenta, Color.Purple.GetClosestConsoleColor());
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkMagenta, Color.RebeccaPurple.GetClosestConsoleColor());
|
||||||
|
#endif
|
||||||
|
Assert.AreEqual(ConsoleColor.Red, Color.Red.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.RosyBrown.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkCyan, Color.RoyalBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkRed, Color.SaddleBrown.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.Salmon.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkYellow, Color.SandyBrown.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkCyan, Color.SeaGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.SeaShell.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkRed, Color.Sienna.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.Silver.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.SkyBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.SlateBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.SlateGray.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Snow.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkCyan, Color.SpringGreen.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.SteelBlue.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.Tan.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkCyan, Color.Teal.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.Thistle.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkYellow, Color.Tomato.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Cyan, Color.Turquoise.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.DarkGray, Color.Violet.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.Wheat.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.White.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.White, Color.WhiteSmoke.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Yellow, Color.Yellow.GetClosestConsoleColor());
|
||||||
|
Assert.AreEqual(ConsoleColor.Gray, Color.YellowGreen.GetClosestConsoleColor());
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Inverted_ShouldReturnInvertedColor()
|
public void Inverted_ShouldReturnInvertedColor()
|
||||||
{
|
{
|
||||||
|
82
X10D.Tests/src/Drawing/CuboidTests.cs
Normal file
82
X10D.Tests/src/Drawing/CuboidTests.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class CuboidTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Corners_ShouldBeCorrect_GivenCubeOfSize1()
|
||||||
|
{
|
||||||
|
Cuboid cube = Cuboid.Cube;
|
||||||
|
|
||||||
|
Assert.AreEqual(new Vector3(0.5f, 0.5f, -0.5f), cube.FrontTopRight);
|
||||||
|
Assert.AreEqual(new Vector3(-0.5f, 0.5f, -0.5f), cube.FrontTopLeft);
|
||||||
|
Assert.AreEqual(new Vector3(0.5f, -0.5f, -0.5f), cube.FrontBottomRight);
|
||||||
|
Assert.AreEqual(new Vector3(-0.5f, -0.5f, -0.5f), cube.FrontBottomLeft);
|
||||||
|
Assert.AreEqual(new Vector3(0.5f, 0.5f, 0.5f), cube.BackTopRight);
|
||||||
|
Assert.AreEqual(new Vector3(-0.5f, 0.5f, 0.5f), cube.BackTopLeft);
|
||||||
|
Assert.AreEqual(new Vector3(0.5f, -0.5f, 0.5f), cube.BackBottomRight);
|
||||||
|
Assert.AreEqual(new Vector3(-0.5f, -0.5f, 0.5f), cube.BackBottomLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoCubesOfSize1()
|
||||||
|
{
|
||||||
|
var cube1 = Cuboid.Cube;
|
||||||
|
var cube2 = Cuboid.Cube;
|
||||||
|
Assert.AreEqual(cube1, cube2);
|
||||||
|
Assert.IsTrue(cube1 == cube2);
|
||||||
|
Assert.IsFalse(cube1 != cube2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentCubes()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual(Cuboid.Cube, Cuboid.Empty);
|
||||||
|
Assert.IsFalse(Cuboid.Cube == Cuboid.Empty);
|
||||||
|
Assert.IsTrue(Cuboid.Cube != Cuboid.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentObjects()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(Cuboid.Cube.Equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Cuboid.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Cuboid.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenCubeOfSize1()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Cuboid.Cube.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Cuboid.Cube.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Size_ShouldBeOne_GivenCubeOfSize1()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(Vector3.One, Cuboid.Cube.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Size_ShouldBeOne_GivenRotatedCube()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(Vector3.One, new Cuboid(0, 0, 0, 1, 1, 1, 90, 0, 0).Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Volume_ShouldBe1_GivenCubeOfSize1()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1.0f, Cuboid.Cube.Volume, 1e-6f);
|
||||||
|
}
|
||||||
|
}
|
156
X10D.Tests/src/Drawing/EllipseFTests.cs
Normal file
156
X10D.Tests/src/Drawing/EllipseFTests.cs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Numerics;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class EllipseFTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Area_ShouldBePiRadiusRadius_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
var unitEllipse = EllipseF.Unit;
|
||||||
|
Assert.AreEqual(MathF.PI, unitEllipse.Area, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ApproximateCircumference_ShouldBe2PiRadius_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
var unitEllipse = EllipseF.Unit;
|
||||||
|
Assert.AreEqual(2 * MathF.PI, unitEllipse.ApproximateCircumference, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Constructor_ShouldGiveCorrectEllipse()
|
||||||
|
{
|
||||||
|
var ellipse = new EllipseF(PointF.Empty, new SizeF(2, 1));
|
||||||
|
Assert.AreEqual(new PointF(0, 0), ellipse.Center);
|
||||||
|
Assert.AreEqual(new SizeF(2, 1), ellipse.Radius);
|
||||||
|
|
||||||
|
ellipse = new EllipseF(0, 0, 2, 1);
|
||||||
|
Assert.AreEqual(new PointF(0, 0), ellipse.Center);
|
||||||
|
Assert.AreEqual(new SizeF(2, 1), ellipse.Radius);
|
||||||
|
|
||||||
|
ellipse = new EllipseF(PointF.Empty, new Vector2(2, 1));
|
||||||
|
Assert.AreEqual(new PointF(0, 0), ellipse.Center);
|
||||||
|
Assert.AreEqual(new SizeF(2, 1), ellipse.Radius);
|
||||||
|
|
||||||
|
ellipse = new EllipseF(Vector2.Zero, new Vector2(2, 1));
|
||||||
|
Assert.AreEqual(new PointF(0, 0), ellipse.Center);
|
||||||
|
Assert.AreEqual(new SizeF(2, 1), ellipse.Radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoUnitEllipses()
|
||||||
|
{
|
||||||
|
var unitEllipse1 = EllipseF.Unit;
|
||||||
|
var unitEllipse2 = EllipseF.Unit;
|
||||||
|
Assert.AreEqual(unitEllipse1, unitEllipse2);
|
||||||
|
Assert.IsTrue(unitEllipse1 == unitEllipse2);
|
||||||
|
Assert.IsFalse(unitEllipse1 != unitEllipse2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentEllipses()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual(EllipseF.Unit, EllipseF.Empty);
|
||||||
|
Assert.IsFalse(EllipseF.Unit == EllipseF.Empty);
|
||||||
|
Assert.IsTrue(EllipseF.Unit != EllipseF.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentObjects()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(EllipseF.Unit.Equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyEllipse()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = EllipseF.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, EllipseF.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = EllipseF.Unit.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, EllipseF.Unit.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void HorizontalRadius_ShouldBe0_GivenEmptyEllipse()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, EllipseF.Empty.HorizontalRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void HorizontalRadius_ShouldBe1_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, EllipseF.Unit.HorizontalRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Explicit_ShouldReturnEquivalentEllipse_GivenEllipse()
|
||||||
|
{
|
||||||
|
EllipseF unitEllipse = EllipseF.Unit;
|
||||||
|
Ellipse converted = (Ellipse)unitEllipse;
|
||||||
|
|
||||||
|
Assert.AreEqual(unitEllipse, converted);
|
||||||
|
Assert.AreEqual(unitEllipse.HorizontalRadius, converted.HorizontalRadius);
|
||||||
|
Assert.AreEqual(unitEllipse.VerticalRadius, converted.VerticalRadius);
|
||||||
|
Assert.AreEqual(unitEllipse.Center, converted.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentEllipse_GivenCircle()
|
||||||
|
{
|
||||||
|
Circle unitCircle = Circle.Unit;
|
||||||
|
EllipseF converted = unitCircle;
|
||||||
|
|
||||||
|
Assert.AreEqual(unitCircle, converted);
|
||||||
|
Assert.AreEqual(unitCircle.Radius, converted.HorizontalRadius);
|
||||||
|
Assert.AreEqual(unitCircle.Radius, converted.VerticalRadius);
|
||||||
|
Assert.AreEqual(unitCircle.Center, converted.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentEllipse_GivenCircleF()
|
||||||
|
{
|
||||||
|
CircleF unitCircle = CircleF.Unit;
|
||||||
|
EllipseF converted = unitCircle;
|
||||||
|
|
||||||
|
Assert.AreEqual(unitCircle, converted);
|
||||||
|
Assert.AreEqual(unitCircle.Radius, converted.HorizontalRadius);
|
||||||
|
Assert.AreEqual(unitCircle.Radius, converted.VerticalRadius);
|
||||||
|
Assert.AreEqual(unitCircle.Center, converted.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentEllipse_GivenEllipse()
|
||||||
|
{
|
||||||
|
Ellipse unitEllipse = Ellipse.Unit;
|
||||||
|
EllipseF converted = unitEllipse;
|
||||||
|
|
||||||
|
Assert.AreEqual(unitEllipse, converted);
|
||||||
|
Assert.AreEqual(unitEllipse.HorizontalRadius, converted.HorizontalRadius);
|
||||||
|
Assert.AreEqual(unitEllipse.VerticalRadius, converted.VerticalRadius);
|
||||||
|
Assert.AreEqual(unitEllipse.Center, converted.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void VerticalRadius_ShouldBe0_GivenEmptyEllipse()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, EllipseF.Empty.VerticalRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void VerticalRadius_ShouldBe1_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, EllipseF.Unit.VerticalRadius);
|
||||||
|
}
|
||||||
|
}
|
111
X10D.Tests/src/Drawing/EllipseTests.cs
Normal file
111
X10D.Tests/src/Drawing/EllipseTests.cs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class EllipseTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Area_ShouldBePiRadiusRadius_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
var unitEllipse = Ellipse.Unit;
|
||||||
|
Assert.AreEqual(MathF.PI, unitEllipse.Area, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ApproximateCircumference_ShouldBe2PiRadius_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
var unitEllipse = Ellipse.Unit;
|
||||||
|
Assert.AreEqual(2 * MathF.PI, unitEllipse.ApproximateCircumference, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Constructor_ShouldGiveCorrectEllipse()
|
||||||
|
{
|
||||||
|
var ellipse = new Ellipse(Point.Empty, new Size(2, 1));
|
||||||
|
Assert.AreEqual(new Point(0, 0), ellipse.Center);
|
||||||
|
Assert.AreEqual(new Size(2, 1), ellipse.Radius);
|
||||||
|
|
||||||
|
ellipse = new Ellipse(0, 0, 2, 1);
|
||||||
|
Assert.AreEqual(new Point(0, 0), ellipse.Center);
|
||||||
|
Assert.AreEqual(new Size(2, 1), ellipse.Radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoUnitEllipses()
|
||||||
|
{
|
||||||
|
var unitEllipse1 = Ellipse.Unit;
|
||||||
|
var unitEllipse2 = Ellipse.Unit;
|
||||||
|
Assert.AreEqual(unitEllipse1, unitEllipse2);
|
||||||
|
Assert.IsTrue(unitEllipse1 == unitEllipse2);
|
||||||
|
Assert.IsFalse(unitEllipse1 != unitEllipse2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentEllipses()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual(Ellipse.Unit, Ellipse.Empty);
|
||||||
|
Assert.IsFalse(Ellipse.Unit == Ellipse.Empty);
|
||||||
|
Assert.IsTrue(Ellipse.Unit != Ellipse.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentObjects()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(Ellipse.Unit.Equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyEllipse()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Ellipse.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Ellipse.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Ellipse.Unit.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Ellipse.Unit.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void HorizontalRadius_ShouldBe0_GivenEmptyEllipse()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, Ellipse.Empty.HorizontalRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void HorizontalRadius_ShouldBe1_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Ellipse.Unit.HorizontalRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentEllipse_GivenCircle()
|
||||||
|
{
|
||||||
|
Circle unitCircle = Circle.Unit;
|
||||||
|
Ellipse converted = unitCircle;
|
||||||
|
|
||||||
|
Assert.AreEqual(unitCircle, converted);
|
||||||
|
Assert.AreEqual(unitCircle.Radius, converted.HorizontalRadius);
|
||||||
|
Assert.AreEqual(unitCircle.Radius, converted.VerticalRadius);
|
||||||
|
Assert.AreEqual(unitCircle.Center, converted.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void VerticalRadius_ShouldBe0_GivenEmptyEllipse()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, Ellipse.Empty.VerticalRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void VerticalRadius_ShouldBe1_GivenUnitEllipse()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Ellipse.Unit.VerticalRadius);
|
||||||
|
}
|
||||||
|
}
|
188
X10D.Tests/src/Drawing/Line3DTests.cs
Normal file
188
X10D.Tests/src/Drawing/Line3DTests.cs
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Numerics;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class Line3DTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenEmptyAndOne()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, Line3D.Empty.CompareTo(Line3D.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenEmptyLineAndOneLineAsObject()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, Line3D.Empty.CompareTo((object)Line3D.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenNull()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Line3D.One.CompareTo(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenOneAndEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Line3D.One.CompareTo(Line3D.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeZero_GivenUnitLine()
|
||||||
|
{
|
||||||
|
var unitLine3D = Line3D.One;
|
||||||
|
Assert.AreEqual(0, unitLine3D.CompareTo(unitLine3D));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldThrowArgumentException_GivenInvalidType()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => Line3D.Empty.CompareTo(new object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe0_GivenEmptyLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0.0f, Line3D.Empty.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe1_GivenUnitXLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1.0f, Line3D.UnitX.Length, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe1_GivenUnitYLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1.0f, Line3D.UnitY.Length, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe1_GivenUnitZLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1.0f, Line3D.UnitZ.Length, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoUnitLines()
|
||||||
|
{
|
||||||
|
Line3D first = Line3D.One;
|
||||||
|
Line3D second = Line3D.One;
|
||||||
|
|
||||||
|
Assert.AreEqual(first, second);
|
||||||
|
Assert.IsTrue(first == second);
|
||||||
|
Assert.IsFalse(first != second);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentLines()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual(Line3D.One, Line3D.Empty);
|
||||||
|
Assert.IsFalse(Line3D.One == Line3D.Empty);
|
||||||
|
Assert.IsTrue(Line3D.One != Line3D.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentObjects()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(Line3D.One.Equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyLine()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Line3D.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Line3D.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenUnitLine()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Line3D.One.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Line3D.One.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Explicit_ShouldReturnEquivalentLine_GivenLine()
|
||||||
|
{
|
||||||
|
Line3D oneLine = new Line3D(Vector3.Zero, Vector3.UnitX + Vector3.UnitY);
|
||||||
|
Line converted = (Line)oneLine;
|
||||||
|
|
||||||
|
var expectedStart = new Point((int)oneLine.Start.X, (int)oneLine.Start.Y);
|
||||||
|
var expectedEnd = new Point((int)oneLine.End.X, (int)oneLine.End.Y);
|
||||||
|
|
||||||
|
Assert.AreEqual(oneLine.Length, converted.Length);
|
||||||
|
Assert.AreEqual(expectedStart, converted.Start);
|
||||||
|
Assert.AreEqual(expectedEnd, converted.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Explicit_ShouldReturnEquivalentLineF_GivenLine()
|
||||||
|
{
|
||||||
|
Line3D oneLine = new Line3D(Vector3.Zero, Vector3.UnitX + Vector3.UnitY);
|
||||||
|
LineF converted = (LineF)oneLine;
|
||||||
|
|
||||||
|
var expectedStart = new PointF(oneLine.Start.X, oneLine.Start.Y);
|
||||||
|
var expectedEnd = new PointF(oneLine.End.X, oneLine.End.Y);
|
||||||
|
|
||||||
|
Assert.AreEqual(oneLine.Length, converted.Length);
|
||||||
|
Assert.AreEqual(expectedStart, converted.Start);
|
||||||
|
Assert.AreEqual(expectedEnd, converted.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_GreaterThan_True_GivenUnitAndEmptyCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Line3D.One > Line3D.Empty);
|
||||||
|
Assert.IsTrue(Line3D.One >= Line3D.Empty);
|
||||||
|
Assert.IsFalse(Line3D.One < Line3D.Empty);
|
||||||
|
Assert.IsFalse(Line3D.One <= Line3D.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentLine_GivenLine()
|
||||||
|
{
|
||||||
|
Line oneLine = Line.One;
|
||||||
|
Line3D converted = oneLine;
|
||||||
|
|
||||||
|
var expectedStart = new Vector3(oneLine.Start.X, oneLine.Start.Y, 0.0f);
|
||||||
|
var expectedEnd = new Vector3(oneLine.End.X, oneLine.End.Y, 0.0f);
|
||||||
|
|
||||||
|
Assert.AreEqual(oneLine, converted);
|
||||||
|
Assert.AreEqual(oneLine.Length, converted.Length);
|
||||||
|
Assert.AreEqual(expectedStart, converted.Start);
|
||||||
|
Assert.AreEqual(expectedEnd, converted.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentLine_GivenLineF()
|
||||||
|
{
|
||||||
|
LineF oneLine = LineF.One;
|
||||||
|
Line3D converted = oneLine;
|
||||||
|
|
||||||
|
var expectedStart = new Vector3(oneLine.Start.X, oneLine.Start.Y, 0.0f);
|
||||||
|
var expectedEnd = new Vector3(oneLine.End.X, oneLine.End.Y, 0.0f);
|
||||||
|
|
||||||
|
Assert.AreEqual(oneLine, converted);
|
||||||
|
Assert.AreEqual(oneLine.Length, converted.Length);
|
||||||
|
Assert.AreEqual(expectedStart, converted.Start);
|
||||||
|
Assert.AreEqual(expectedEnd, converted.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_LessThan_True_GivenEmptyAndUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Line3D.Empty < Line3D.One);
|
||||||
|
Assert.IsTrue(Line3D.Empty <= Line3D.One);
|
||||||
|
Assert.IsFalse(Line3D.Empty > Line3D.One);
|
||||||
|
Assert.IsFalse(Line3D.Empty >= Line3D.One);
|
||||||
|
}
|
||||||
|
}
|
146
X10D.Tests/src/Drawing/LineFTests.cs
Normal file
146
X10D.Tests/src/Drawing/LineFTests.cs
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class LineFTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenEmptyAndOne()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, LineF.Empty.CompareTo(LineF.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenEmptyLineAndOneLineAsObject()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, LineF.Empty.CompareTo((object)LineF.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenNull()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, LineF.One.CompareTo(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenOneAndEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, LineF.One.CompareTo(LineF.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeZero_GivenUnitLine()
|
||||||
|
{
|
||||||
|
var unitLineF = LineF.One;
|
||||||
|
Assert.AreEqual(0, unitLineF.CompareTo(unitLineF));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldThrowArgumentException_GivenInvalidType()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => LineF.Empty.CompareTo(new object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe0_GivenEmptyLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0.0f, LineF.Empty.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe1_GivenUnitXLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1.0f, LineF.UnitX.Length, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe1_GivenUnitYLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1.0f, LineF.UnitY.Length, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoUnitLines()
|
||||||
|
{
|
||||||
|
LineF first = LineF.One;
|
||||||
|
LineF second = LineF.One;
|
||||||
|
|
||||||
|
Assert.AreEqual(first, second);
|
||||||
|
Assert.IsTrue(first == second);
|
||||||
|
Assert.IsFalse(first != second);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentLines()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual(LineF.One, LineF.Empty);
|
||||||
|
Assert.IsFalse(LineF.One == LineF.Empty);
|
||||||
|
Assert.IsTrue(LineF.One != LineF.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentObjects()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(LineF.One.Equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyLine()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = LineF.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, LineF.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenUnitLine()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = LineF.One.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, LineF.One.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Explicit_ShouldReturnEquivalentLine_GivenLine()
|
||||||
|
{
|
||||||
|
LineF oneLine = LineF.One;
|
||||||
|
Line converted = (Line)oneLine;
|
||||||
|
|
||||||
|
Assert.AreEqual(oneLine, converted);
|
||||||
|
Assert.AreEqual(oneLine.Length, converted.Length);
|
||||||
|
Assert.AreEqual(oneLine.Start, converted.Start);
|
||||||
|
Assert.AreEqual(oneLine.End, converted.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_GreaterThan_True_GivenUnitAndEmptyCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(LineF.One > LineF.Empty);
|
||||||
|
Assert.IsTrue(LineF.One >= LineF.Empty);
|
||||||
|
Assert.IsFalse(LineF.One < LineF.Empty);
|
||||||
|
Assert.IsFalse(LineF.One <= LineF.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentLine_GivenLine()
|
||||||
|
{
|
||||||
|
Line oneLine = Line.One;
|
||||||
|
LineF converted = oneLine;
|
||||||
|
|
||||||
|
Assert.AreEqual(oneLine, converted);
|
||||||
|
Assert.AreEqual(oneLine.Length, converted.Length);
|
||||||
|
Assert.AreEqual(oneLine.Start, converted.Start);
|
||||||
|
Assert.AreEqual(oneLine.End, converted.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_LessThan_True_GivenEmptyAndUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(LineF.Empty < LineF.One);
|
||||||
|
Assert.IsTrue(LineF.Empty <= LineF.One);
|
||||||
|
Assert.IsFalse(LineF.Empty > LineF.One);
|
||||||
|
Assert.IsFalse(LineF.Empty >= LineF.One);
|
||||||
|
}
|
||||||
|
}
|
122
X10D.Tests/src/Drawing/LineTests.cs
Normal file
122
X10D.Tests/src/Drawing/LineTests.cs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class LineTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenEmptyAndOne()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, Line.Empty.CompareTo(Line.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenEmptyLineAndOneLineAsObject()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, Line.Empty.CompareTo((object)Line.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenNull()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Line.One.CompareTo(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenOneAndEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Line.One.CompareTo(Line.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeZero_GivenUnitLine()
|
||||||
|
{
|
||||||
|
var unitLine = Line.One;
|
||||||
|
Assert.AreEqual(0, unitLine.CompareTo(unitLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldThrowArgumentException_GivenInvalidType()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => Line.Empty.CompareTo(new object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoUnitLines()
|
||||||
|
{
|
||||||
|
Line first = Line.One;
|
||||||
|
Line second = Line.One;
|
||||||
|
|
||||||
|
Assert.AreEqual(first, second);
|
||||||
|
Assert.IsTrue(first == second);
|
||||||
|
Assert.IsFalse(first != second);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentLines()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual(Line.One, Line.Empty);
|
||||||
|
Assert.IsFalse(Line.One == Line.Empty);
|
||||||
|
Assert.IsTrue(Line.One != Line.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentObjects()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(Line.One.Equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyLine()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Line.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Line.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenUnitLine()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Line.One.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Line.One.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe0_GivenEmptyLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0.0f, Line.Empty.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe1_GivenUnitXLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1.0f, Line.UnitX.Length, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Length_ShouldBe1_GivenUnitYLine()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1.0f, Line.UnitY.Length, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_GreaterThan_True_GivenUnitAndEmptyCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Line.One > Line.Empty);
|
||||||
|
Assert.IsTrue(Line.One >= Line.Empty);
|
||||||
|
Assert.IsFalse(Line.One < Line.Empty);
|
||||||
|
Assert.IsFalse(Line.One <= Line.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_LessThan_True_GivenEmptyAndUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Line.Empty < Line.One);
|
||||||
|
Assert.IsTrue(Line.Empty <= Line.One);
|
||||||
|
Assert.IsFalse(Line.Empty > Line.One);
|
||||||
|
Assert.IsFalse(Line.Empty >= Line.One);
|
||||||
|
}
|
||||||
|
}
|
65
X10D.Tests/src/Drawing/PointFTests.cs
Normal file
65
X10D.Tests/src/Drawing/PointFTests.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
#if !NET6_0_OR_GREATER
|
||||||
|
using X10D.Core;
|
||||||
|
#endif
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class PointFTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void IsOnLine_ShouldReturnTrue_GivenPointOnLine()
|
||||||
|
{
|
||||||
|
var point = new PointF(1.0f, 0.0f);
|
||||||
|
var line = new LineF(PointF.Empty, new PointF(2.0f, 0.0f));
|
||||||
|
|
||||||
|
Assert.IsTrue(point.IsOnLine(line));
|
||||||
|
Assert.IsTrue(point.IsOnLine(line.Start, line.End));
|
||||||
|
Assert.IsTrue(point.IsOnLine(line.Start.ToVector2(), line.End.ToVector2()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsOnLine_ShouldReturnFalse_GivenPointNotOnLine()
|
||||||
|
{
|
||||||
|
var point = new PointF(1.0f, 1.0f);
|
||||||
|
var line = new LineF(PointF.Empty, new PointF(2.0f, 0.0f));
|
||||||
|
|
||||||
|
Assert.IsFalse(point.IsOnLine(line));
|
||||||
|
Assert.IsFalse(point.IsOnLine(line.Start, line.End));
|
||||||
|
Assert.IsFalse(point.IsOnLine(line.Start.ToVector2(), line.End.ToVector2()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Round_ShouldRoundToNearestInteger_GivenNoParameters()
|
||||||
|
{
|
||||||
|
var point = new PointF(1.5f, 2.6f);
|
||||||
|
var rounded = point.Round();
|
||||||
|
|
||||||
|
Assert.AreEqual(2, rounded.X);
|
||||||
|
Assert.AreEqual(3, rounded.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Round_ShouldRoundToNearest10_GivenPrecision10()
|
||||||
|
{
|
||||||
|
var point = new PointF(1.5f, 25.2f);
|
||||||
|
var rounded = point.Round(10);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, rounded.X);
|
||||||
|
Assert.AreEqual(30, rounded.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ToSizeF_ShouldReturnSize_WithEquivalentMembers()
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
var point = new PointF(random.NextSingle(), random.NextSingle());
|
||||||
|
var size = point.ToSizeF();
|
||||||
|
|
||||||
|
Assert.AreEqual(point.X, size.Width, 1e-6f);
|
||||||
|
Assert.AreEqual(point.Y, size.Height, 1e-6f);
|
||||||
|
}
|
||||||
|
}
|
64
X10D.Tests/src/Drawing/PointTests.cs
Normal file
64
X10D.Tests/src/Drawing/PointTests.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class PointTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void IsOnLine_ShouldReturnTrue_GivenPointOnLine()
|
||||||
|
{
|
||||||
|
var point = new Point(1, 0);
|
||||||
|
var line = new Line(Point.Empty, new Point(2, 0));
|
||||||
|
|
||||||
|
Assert.IsTrue(point.IsOnLine(line));
|
||||||
|
Assert.IsTrue(point.IsOnLine(line.Start, line.End));
|
||||||
|
Assert.IsTrue(point.IsOnLine(line.Start.ToVector2(), line.End.ToVector2()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsOnLine_ShouldReturnFalse_GivenPointNotOnLine()
|
||||||
|
{
|
||||||
|
var point = new Point(1, 1);
|
||||||
|
var line = new Line(Point.Empty, new Point(2, 0));
|
||||||
|
|
||||||
|
Assert.IsFalse(point.IsOnLine(line));
|
||||||
|
Assert.IsFalse(point.IsOnLine(line.Start, line.End));
|
||||||
|
Assert.IsFalse(point.IsOnLine(line.Start.ToVector2(), line.End.ToVector2()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ToSize_ShouldReturnSize_WithEquivalentMembers()
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
var point = new Point(random.Next(), random.Next());
|
||||||
|
var size = point.ToSize();
|
||||||
|
|
||||||
|
Assert.AreEqual(point.X, size.Width);
|
||||||
|
Assert.AreEqual(point.Y, size.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ToSizeF_ShouldReturnSize_WithEquivalentMembers()
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
var point = new Point(random.Next(), random.Next());
|
||||||
|
var size = point.ToSizeF();
|
||||||
|
|
||||||
|
Assert.AreEqual(point.X, size.Width, 1e-6f);
|
||||||
|
Assert.AreEqual(point.Y, size.Height, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ToVector2_ShouldReturnVector_WithEquivalentMembers()
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
var point = new Point(random.Next(), random.Next());
|
||||||
|
var size = point.ToVector2();
|
||||||
|
|
||||||
|
Assert.AreEqual(point.X, size.X, 1e-6f);
|
||||||
|
Assert.AreEqual(point.Y, size.Y, 1e-6f);
|
||||||
|
}
|
||||||
|
}
|
247
X10D.Tests/src/Drawing/PolygonFTests.cs
Normal file
247
X10D.Tests/src/Drawing/PolygonFTests.cs
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Numerics;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class PolygonFTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void AddVertices_ShouldAddVertices()
|
||||||
|
{
|
||||||
|
var polygon = PolygonF.Empty;
|
||||||
|
polygon.AddVertices(new[] {new PointF(1, 2), new PointF(3, 4)});
|
||||||
|
Assert.AreEqual(2, polygon.VertexCount);
|
||||||
|
|
||||||
|
// assert that the empty polygon was not modified
|
||||||
|
Assert.AreEqual(0, PolygonF.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddVertices_ShouldThrowArgumentNullException_GivenNullEnumerableOfPointF()
|
||||||
|
{
|
||||||
|
var polygon = PolygonF.Empty;
|
||||||
|
IEnumerable<PointF> vertices = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => polygon.AddVertices(vertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddVertices_ShouldThrowArgumentNullException_GivenNullEnumerableOfVector2()
|
||||||
|
{
|
||||||
|
var polygon = PolygonF.Empty;
|
||||||
|
IEnumerable<Vector2> vertices = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => polygon.AddVertices(vertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ClearVertices_ShouldClearVertices()
|
||||||
|
{
|
||||||
|
var polygon = PolygonF.Empty;
|
||||||
|
polygon.AddVertices(new[] {new Vector2(1, 2), new Vector2(3, 4)});
|
||||||
|
Assert.AreEqual(2, polygon.VertexCount);
|
||||||
|
|
||||||
|
// assert that the empty polygon was not modified
|
||||||
|
Assert.AreEqual(0, PolygonF.Empty.VertexCount);
|
||||||
|
|
||||||
|
polygon.ClearVertices();
|
||||||
|
Assert.AreEqual(0, polygon.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Constructor_ShouldPopulateVertices_GivenPolygon()
|
||||||
|
{
|
||||||
|
var pointPolygon = new PolygonF(new[] {new PointF(1, 2), new PointF(3, 4)});
|
||||||
|
var vectorPolygon = new PolygonF(new[] {new Vector2(1, 2), new Vector2(3, 4)});
|
||||||
|
|
||||||
|
Assert.AreEqual(2, pointPolygon.VertexCount);
|
||||||
|
Assert.AreEqual(2, vectorPolygon.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Constructor_ShouldThrowArgumentNullException_GivenNullEnumerableOfPointF()
|
||||||
|
{
|
||||||
|
IEnumerable<PointF> vertices = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => new PolygonF(vertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Constructor_ShouldThrowArgumentNullException_GivenNullEnumerableOfVector2()
|
||||||
|
{
|
||||||
|
IEnumerable<Vector2> vertices = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => new PolygonF(vertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CopyConstructor_ShouldCopyVertices_GivenPolygon()
|
||||||
|
{
|
||||||
|
var first = PolygonF.Empty;
|
||||||
|
first.AddVertices(new[] {new PointF(1, 2), new PointF(3, 4)});
|
||||||
|
|
||||||
|
var second = new PolygonF(first);
|
||||||
|
Assert.AreEqual(2, first.VertexCount);
|
||||||
|
Assert.AreEqual(2, second.VertexCount);
|
||||||
|
|
||||||
|
// we cannot use CollectionAssert here for reasons I am not entirely sure of.
|
||||||
|
// it seems to dislike casting from IReadOnlyList<Point> to ICollection. but okay.
|
||||||
|
Assert.IsTrue(first.Vertices.SequenceEqual(second.Vertices));
|
||||||
|
|
||||||
|
// assert that the empty polygon was not modified
|
||||||
|
Assert.AreEqual(0, PolygonF.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CopyConstructor_ShouldThrowArgumentNullException_GivenNullPolygonF()
|
||||||
|
{
|
||||||
|
PolygonF polygon = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => new PolygonF(polygon));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoEmptyPolygons()
|
||||||
|
{
|
||||||
|
var first = PolygonF.Empty;
|
||||||
|
var second = PolygonF.Empty;
|
||||||
|
|
||||||
|
Assert.AreEqual(first, second);
|
||||||
|
Assert.AreEqual(second, first);
|
||||||
|
Assert.IsTrue(first.Equals(second));
|
||||||
|
Assert.IsTrue(second.Equals(first));
|
||||||
|
Assert.IsTrue(first == second);
|
||||||
|
Assert.IsTrue(second == first);
|
||||||
|
Assert.IsFalse(first != second);
|
||||||
|
Assert.IsFalse(second != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoHexagons()
|
||||||
|
{
|
||||||
|
PolygonF first = CreateHexagon();
|
||||||
|
PolygonF second = CreateHexagon();
|
||||||
|
|
||||||
|
Assert.AreEqual(first, second);
|
||||||
|
Assert.AreEqual(second, first);
|
||||||
|
Assert.IsTrue(first.Equals(second));
|
||||||
|
Assert.IsTrue(second.Equals(first));
|
||||||
|
Assert.IsTrue(first == second);
|
||||||
|
Assert.IsTrue(second == first);
|
||||||
|
Assert.IsFalse(first != second);
|
||||||
|
Assert.IsFalse(second != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenHexagonAndEmptyPolygon()
|
||||||
|
{
|
||||||
|
PolygonF first = CreateHexagon();
|
||||||
|
PolygonF second = PolygonF.Empty;
|
||||||
|
|
||||||
|
Assert.AreNotEqual(first, second);
|
||||||
|
Assert.AreNotEqual(second, first);
|
||||||
|
Assert.IsFalse(first.Equals(second));
|
||||||
|
Assert.IsFalse(second.Equals(first));
|
||||||
|
Assert.IsFalse(first == second);
|
||||||
|
Assert.IsFalse(second == first);
|
||||||
|
Assert.IsTrue(first != second);
|
||||||
|
Assert.IsTrue(second != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FromPolygon_ShouldThrowArgumentNullException_GivenNullPolygonF()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => PolygonF.FromPolygon(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsConvex_ShouldBeFalse_GivenEmptyPolygon()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(PolygonF.Empty.IsConvex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsConvex_ShouldBeTrue_GivenHexagon()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(CreateHexagon().IsConvex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsConvex_ShouldBeFalse_GivenConcavePolygon()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(CreateConcavePolygon().IsConvex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Explicit_ShouldReturnEquivalentCircle_GivenCircle()
|
||||||
|
{
|
||||||
|
PolygonF polygon = CreateHexagon();
|
||||||
|
Polygon converted = (Polygon)polygon;
|
||||||
|
|
||||||
|
Assert.AreEqual(polygon, converted);
|
||||||
|
Assert.AreEqual(polygon.IsConvex, converted.IsConvex);
|
||||||
|
Assert.AreEqual(polygon.VertexCount, converted.VertexCount);
|
||||||
|
|
||||||
|
Assert.IsTrue(polygon.Vertices.SequenceEqual(converted.Vertices.Select(p => (PointF)p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentCircle_GivenCircle()
|
||||||
|
{
|
||||||
|
Polygon polygon = PolygonTests.CreateHexagon();
|
||||||
|
PolygonF converted = polygon;
|
||||||
|
|
||||||
|
Assert.AreEqual(polygon, converted);
|
||||||
|
Assert.AreEqual(polygon.IsConvex, converted.IsConvex);
|
||||||
|
Assert.AreEqual(polygon.VertexCount, converted.VertexCount);
|
||||||
|
|
||||||
|
Assert.IsTrue(converted.Vertices.SequenceEqual(polygon.Vertices.Select(p => (PointF)p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PointCount_ShouldBe1_GivenPolygonFWith1Point()
|
||||||
|
{
|
||||||
|
var polygon = new PolygonF();
|
||||||
|
polygon.AddVertex(new Point(1, 1));
|
||||||
|
|
||||||
|
Assert.AreEqual(1, polygon.VertexCount);
|
||||||
|
|
||||||
|
// assert that the empty polygon was not modified
|
||||||
|
Assert.AreEqual(0, PolygonF.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PointCount_ShouldBe0_GivenEmptyPolygon()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, PolygonF.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = PolygonF.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, PolygonF.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static PolygonF CreateHexagon()
|
||||||
|
{
|
||||||
|
var hexagon = new PolygonF();
|
||||||
|
hexagon.AddVertex(new Vector2(0, 0));
|
||||||
|
hexagon.AddVertex(new Vector2(1, 0));
|
||||||
|
hexagon.AddVertex(new Vector2(1, 1));
|
||||||
|
hexagon.AddVertex(new Vector2(0, 1));
|
||||||
|
hexagon.AddVertex(new Vector2(-1, 1));
|
||||||
|
hexagon.AddVertex(new Vector2(-1, 0));
|
||||||
|
return hexagon;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static PolygonF CreateConcavePolygon()
|
||||||
|
{
|
||||||
|
var hexagon = new PolygonF();
|
||||||
|
hexagon.AddVertex(new Vector2(0, 0));
|
||||||
|
hexagon.AddVertex(new Vector2(2, 0));
|
||||||
|
hexagon.AddVertex(new Vector2(1, 1));
|
||||||
|
hexagon.AddVertex(new Vector2(2, 1));
|
||||||
|
hexagon.AddVertex(new Vector2(0, 1));
|
||||||
|
return hexagon;
|
||||||
|
}
|
||||||
|
}
|
228
X10D.Tests/src/Drawing/PolygonTests.cs
Normal file
228
X10D.Tests/src/Drawing/PolygonTests.cs
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Numerics;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class PolygonTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void AddVertices_ShouldAddVertices()
|
||||||
|
{
|
||||||
|
var polygon = Polygon.Empty;
|
||||||
|
polygon.AddVertices(new[] {new Point(1, 2), new Point(3, 4)});
|
||||||
|
Assert.AreEqual(2, polygon.VertexCount);
|
||||||
|
|
||||||
|
|
||||||
|
// assert that the empty polygon was not modified
|
||||||
|
Assert.AreEqual(0, Polygon.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddVertices_ShouldThrowArgumentNullException_GivenNullEnumerable()
|
||||||
|
{
|
||||||
|
var polygon = Polygon.Empty;
|
||||||
|
IEnumerable<Point> vertices = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => polygon.AddVertices(vertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ClearVertices_ShouldClearVertices()
|
||||||
|
{
|
||||||
|
var polygon = Polygon.Empty;
|
||||||
|
polygon.AddVertices(new[] {new Point(1, 2), new Point(3, 4)});
|
||||||
|
Assert.AreEqual(2, polygon.VertexCount);
|
||||||
|
|
||||||
|
// assert that the empty polygon was not modified
|
||||||
|
Assert.AreEqual(0, Polygon.Empty.VertexCount);
|
||||||
|
|
||||||
|
polygon.ClearVertices();
|
||||||
|
Assert.AreEqual(0, polygon.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Constructor_ShouldPopulateVertices_GivenPolygon()
|
||||||
|
{
|
||||||
|
var pointPolygon = new Polygon(new[] {new Point(1, 2), new Point(3, 4)});
|
||||||
|
|
||||||
|
Assert.AreEqual(2, pointPolygon.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Constructor_ShouldThrowArgumentNullException_GivenNullEnumerableOfPoint()
|
||||||
|
{
|
||||||
|
IEnumerable<Point> vertices = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => new Polygon(vertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CopyConstructor_ShouldCopyVertices_GivenPolygon()
|
||||||
|
{
|
||||||
|
var first = Polygon.Empty;
|
||||||
|
first.AddVertices(new[] {new Point(1, 2), new Point(3, 4)});
|
||||||
|
|
||||||
|
var second = new Polygon(first);
|
||||||
|
Assert.AreEqual(2, first.VertexCount);
|
||||||
|
Assert.AreEqual(2, second.VertexCount);
|
||||||
|
|
||||||
|
// we cannot use CollectionAssert here for reasons I am not entirely sure of.
|
||||||
|
// it seems to dislike casting from IReadOnlyList<Point> to ICollection. but okay.
|
||||||
|
Assert.IsTrue(first.Vertices.SequenceEqual(second.Vertices));
|
||||||
|
|
||||||
|
// assert that the empty polygon was not modified
|
||||||
|
Assert.AreEqual(0, Polygon.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CopyConstructor_ShouldThrowArgumentNullException_GivenNullPolygon()
|
||||||
|
{
|
||||||
|
Polygon polygon = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => new Polygon(polygon));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoEmptyPolygons()
|
||||||
|
{
|
||||||
|
var first = Polygon.Empty;
|
||||||
|
var second = Polygon.Empty;
|
||||||
|
|
||||||
|
Assert.AreEqual(first, second);
|
||||||
|
Assert.AreEqual(second, first);
|
||||||
|
Assert.IsTrue(first.Equals(second));
|
||||||
|
Assert.IsTrue(second.Equals(first));
|
||||||
|
Assert.IsTrue(first == second);
|
||||||
|
Assert.IsTrue(second == first);
|
||||||
|
Assert.IsFalse(first != second);
|
||||||
|
Assert.IsFalse(second != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoHexagons()
|
||||||
|
{
|
||||||
|
Polygon first = CreateHexagon();
|
||||||
|
Polygon second = CreateHexagon();
|
||||||
|
|
||||||
|
Assert.AreEqual(first, second);
|
||||||
|
Assert.AreEqual(second, first);
|
||||||
|
Assert.IsTrue(first.Equals(second));
|
||||||
|
Assert.IsTrue(second.Equals(first));
|
||||||
|
Assert.IsTrue(first == second);
|
||||||
|
Assert.IsTrue(second == first);
|
||||||
|
Assert.IsFalse(first != second);
|
||||||
|
Assert.IsFalse(second != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenHexagonAndEmptyPolygon()
|
||||||
|
{
|
||||||
|
Polygon first = CreateHexagon();
|
||||||
|
Polygon second = Polygon.Empty;
|
||||||
|
|
||||||
|
Assert.AreNotEqual(first, second);
|
||||||
|
Assert.AreNotEqual(second, first);
|
||||||
|
Assert.IsFalse(first.Equals(second));
|
||||||
|
Assert.IsFalse(second.Equals(first));
|
||||||
|
Assert.IsFalse(first == second);
|
||||||
|
Assert.IsFalse(second == first);
|
||||||
|
Assert.IsTrue(first != second);
|
||||||
|
Assert.IsTrue(second != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FromPolygonF_ShouldReturnEquivalentPolygon_GivenPolygon()
|
||||||
|
{
|
||||||
|
PolygonF hexagon = CreateHexagonF();
|
||||||
|
|
||||||
|
Polygon expected = CreateHexagon();
|
||||||
|
Polygon actual = Polygon.FromPolygonF(hexagon);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FromPolygonF_ShouldThrowArgumentNullException_GivenNullPolygon()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => Polygon.FromPolygonF(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsConvex_ShouldBeFalse_GivenEmptyPolygon()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(Polygon.Empty.IsConvex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsConvex_ShouldBeTrue_GivenHexagon()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(CreateHexagon().IsConvex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsConvex_ShouldBeFalse_GivenConcavePolygon()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(CreateConcavePolygon().IsConvex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PointCount_ShouldBe1_GivenPolygonWith1Point()
|
||||||
|
{
|
||||||
|
var polygon = Polygon.Empty;
|
||||||
|
polygon.AddVertex(new Point(1, 1));
|
||||||
|
|
||||||
|
Assert.AreEqual(1, polygon.VertexCount);
|
||||||
|
|
||||||
|
// assert that the empty polygon was not modified
|
||||||
|
Assert.AreEqual(0, Polygon.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PointCount_ShouldBe0_GivenEmptyPolygon()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, Polygon.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Polygon.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Polygon.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Polygon CreateHexagon()
|
||||||
|
{
|
||||||
|
var hexagon = new Polygon();
|
||||||
|
hexagon.AddVertex(new Point(0, 0));
|
||||||
|
hexagon.AddVertex(new Point(1, 0));
|
||||||
|
hexagon.AddVertex(new Point(1, 1));
|
||||||
|
hexagon.AddVertex(new Point(0, 1));
|
||||||
|
hexagon.AddVertex(new Point(-1, 1));
|
||||||
|
hexagon.AddVertex(new Point(-1, 0));
|
||||||
|
return hexagon;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static PolygonF CreateHexagonF()
|
||||||
|
{
|
||||||
|
var hexagon = new PolygonF();
|
||||||
|
hexagon.AddVertex(new PointF(0, 0));
|
||||||
|
hexagon.AddVertex(new PointF(1, 0));
|
||||||
|
hexagon.AddVertex(new PointF(1, 1));
|
||||||
|
hexagon.AddVertex(new PointF(0, 1));
|
||||||
|
hexagon.AddVertex(new PointF(-1, 1));
|
||||||
|
hexagon.AddVertex(new PointF(-1, 0));
|
||||||
|
return hexagon;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Polygon CreateConcavePolygon()
|
||||||
|
{
|
||||||
|
var hexagon = new Polygon();
|
||||||
|
hexagon.AddVertex(new Point(0, 0));
|
||||||
|
hexagon.AddVertex(new Point(2, 0));
|
||||||
|
hexagon.AddVertex(new Point(1, 1));
|
||||||
|
hexagon.AddVertex(new Point(2, 1));
|
||||||
|
hexagon.AddVertex(new Point(0, 1));
|
||||||
|
return hexagon;
|
||||||
|
}
|
||||||
|
}
|
215
X10D.Tests/src/Drawing/PolyhedronTests.cs
Normal file
215
X10D.Tests/src/Drawing/PolyhedronTests.cs
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class PolyhedronTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void AddVertices_ShouldAddVertices()
|
||||||
|
{
|
||||||
|
var polyhedron = Polyhedron.Empty;
|
||||||
|
polyhedron.AddVertices(new[] {new Vector3(1, 2, 3), new Vector3(4, 5, 6)});
|
||||||
|
Assert.AreEqual(2, polyhedron.VertexCount);
|
||||||
|
|
||||||
|
// assert that the empty polyhedron was not modified
|
||||||
|
Assert.AreEqual(0, Polyhedron.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddVertices_ShouldThrowArgumentNullException_GivenNullEnumerableOfVector3()
|
||||||
|
{
|
||||||
|
var polygon = Polyhedron.Empty;
|
||||||
|
IEnumerable<Vector3> vertices = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => polygon.AddVertices(vertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ClearVertices_ShouldClearVertices()
|
||||||
|
{
|
||||||
|
var polyhedron = Polyhedron.Empty;
|
||||||
|
polyhedron.AddVertices(new[] {new Vector3(1, 2, 3), new Vector3(4, 5, 6)});
|
||||||
|
Assert.AreEqual(2, polyhedron.VertexCount);
|
||||||
|
|
||||||
|
// assert that the empty polyhedron was not modified
|
||||||
|
Assert.AreEqual(0, Polyhedron.Empty.VertexCount);
|
||||||
|
|
||||||
|
polyhedron.ClearVertices();
|
||||||
|
Assert.AreEqual(0, polyhedron.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Constructor_ShouldPopulateVertices_GivenPolyhedron()
|
||||||
|
{
|
||||||
|
var polyhedron = new Polyhedron(new[] {new Vector3(1, 2, 3), new Vector3(4, 5, 6)});
|
||||||
|
Assert.AreEqual(2, polyhedron.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Constructor_ShouldThrowArgumentNullException_GivenNullEnumerableOfVector3()
|
||||||
|
{
|
||||||
|
IEnumerable<Vector3> vertices = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => new Polyhedron(vertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CopyConstructor_ShouldCopyVertices_GivenPolyhedron()
|
||||||
|
{
|
||||||
|
var first = Polyhedron.Empty;
|
||||||
|
first.AddVertices(new[] {new Vector3(1, 2, 3), new Vector3(4, 5, 6)});
|
||||||
|
|
||||||
|
var second = new Polyhedron(first);
|
||||||
|
Assert.AreEqual(2, first.VertexCount);
|
||||||
|
Assert.AreEqual(2, second.VertexCount);
|
||||||
|
|
||||||
|
// we cannot use CollectionAssert here for reasons I am not entirely sure of.
|
||||||
|
// it seems to dislike casting from IReadOnlyList<Point> to ICollection. but okay.
|
||||||
|
Assert.IsTrue(first.Vertices.SequenceEqual(second.Vertices));
|
||||||
|
|
||||||
|
// assert that the empty polyhedron was not modified
|
||||||
|
Assert.AreEqual(0, Polyhedron.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoEmptyPolyhedrons()
|
||||||
|
{
|
||||||
|
var first = Polyhedron.Empty;
|
||||||
|
var second = Polyhedron.Empty;
|
||||||
|
|
||||||
|
Assert.AreEqual(first, second);
|
||||||
|
Assert.AreEqual(second, first);
|
||||||
|
Assert.IsTrue(first.Equals(second));
|
||||||
|
Assert.IsTrue(second.Equals(first));
|
||||||
|
Assert.IsTrue(first == second);
|
||||||
|
Assert.IsTrue(second == first);
|
||||||
|
Assert.IsFalse(first != second);
|
||||||
|
Assert.IsFalse(second != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoHexagons()
|
||||||
|
{
|
||||||
|
Polyhedron first = CreateHexagon();
|
||||||
|
Polyhedron second = CreateHexagon();
|
||||||
|
|
||||||
|
Assert.AreEqual(first, second);
|
||||||
|
Assert.AreEqual(second, first);
|
||||||
|
Assert.IsTrue(first.Equals(second));
|
||||||
|
Assert.IsTrue(second.Equals(first));
|
||||||
|
Assert.IsTrue(first == second);
|
||||||
|
Assert.IsTrue(second == first);
|
||||||
|
Assert.IsFalse(first != second);
|
||||||
|
Assert.IsFalse(second != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenHexagonAndEmptyPolyhedron()
|
||||||
|
{
|
||||||
|
Polyhedron first = CreateHexagon();
|
||||||
|
Polyhedron second = Polyhedron.Empty;
|
||||||
|
|
||||||
|
Assert.AreNotEqual(first, second);
|
||||||
|
Assert.AreNotEqual(second, first);
|
||||||
|
Assert.IsFalse(first.Equals(second));
|
||||||
|
Assert.IsFalse(second.Equals(first));
|
||||||
|
Assert.IsFalse(first == second);
|
||||||
|
Assert.IsFalse(second == first);
|
||||||
|
Assert.IsTrue(first != second);
|
||||||
|
Assert.IsTrue(second != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FromPolygon_ShouldThrowArgumentNullException_GivenNullPolygonF()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => Polyhedron.FromPolygon(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FromPolygonF_ShouldThrowArgumentNullException_GivenNullPolygonF()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => Polyhedron.FromPolygonF(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentPolyhedron_GivenPolyhedron()
|
||||||
|
{
|
||||||
|
Polygon polygon = PolygonTests.CreateHexagon();
|
||||||
|
Polyhedron converted = polygon;
|
||||||
|
|
||||||
|
Assert.AreEqual(polygon, converted);
|
||||||
|
Assert.AreEqual(polygon.VertexCount, converted.VertexCount);
|
||||||
|
|
||||||
|
Assert.IsTrue(converted.Vertices.SequenceEqual(polygon.Vertices.Select(p =>
|
||||||
|
{
|
||||||
|
var point = p.ToVector2();
|
||||||
|
return new Vector3(point.X, point.Y, 0);
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_Implicit_ShouldReturnEquivalentPolyhedron_GivenPolyhedronF()
|
||||||
|
{
|
||||||
|
PolygonF polygon = PolygonFTests.CreateHexagon();
|
||||||
|
Polyhedron converted = polygon;
|
||||||
|
|
||||||
|
Assert.AreEqual(polygon, converted);
|
||||||
|
Assert.AreEqual(polygon.VertexCount, converted.VertexCount);
|
||||||
|
|
||||||
|
Assert.IsTrue(converted.Vertices.SequenceEqual(polygon.Vertices.Select(v =>
|
||||||
|
{
|
||||||
|
var point = v.ToVector2();
|
||||||
|
return new Vector3(point.X, point.Y, 0);
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PointCount_ShouldBe1_GivenPolyhedronWith1Point()
|
||||||
|
{
|
||||||
|
var polyhedron = new Polyhedron();
|
||||||
|
polyhedron.AddVertex(Vector3.One);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, polyhedron.VertexCount);
|
||||||
|
|
||||||
|
// assert that the empty polyhedron was not modified
|
||||||
|
Assert.AreEqual(0, Polyhedron.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PointCount_ShouldBe0_GivenEmptyPolyhedron()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, Polyhedron.Empty.VertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Polyhedron.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Polyhedron.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Polyhedron CreateHexagon()
|
||||||
|
{
|
||||||
|
var hexagon = new Polyhedron();
|
||||||
|
hexagon.AddVertex(new Vector3(0, 0, 0));
|
||||||
|
hexagon.AddVertex(new Vector3(1, 0, 0));
|
||||||
|
hexagon.AddVertex(new Vector3(1, 1, 0));
|
||||||
|
hexagon.AddVertex(new Vector3(0, 1, 0));
|
||||||
|
hexagon.AddVertex(new Vector3(-1, 1, 0));
|
||||||
|
hexagon.AddVertex(new Vector3(-1, 0, 0));
|
||||||
|
return hexagon;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Polyhedron CreateConcavePolyhedron()
|
||||||
|
{
|
||||||
|
var hexagon = new Polyhedron();
|
||||||
|
hexagon.AddVertex(new Vector3(0, 0, 0));
|
||||||
|
hexagon.AddVertex(new Vector3(2, 0, 0));
|
||||||
|
hexagon.AddVertex(new Vector3(2, 1, 0));
|
||||||
|
hexagon.AddVertex(new Vector3(2, 1, 0));
|
||||||
|
hexagon.AddVertex(new Vector3(0, 1, 0));
|
||||||
|
return hexagon;
|
||||||
|
}
|
||||||
|
}
|
42
X10D.Tests/src/Drawing/SizeTests.cs
Normal file
42
X10D.Tests/src/Drawing/SizeTests.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class SizeTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ToPoint_ShouldReturnPoint_WithEquivalentMembers()
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
var size = new Size(random.Next(), random.Next());
|
||||||
|
var point = size.ToPoint();
|
||||||
|
|
||||||
|
Assert.AreEqual(size.Width, point.X);
|
||||||
|
Assert.AreEqual(size.Height, point.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ToPointF_ShouldReturnPoint_WithEquivalentMembers()
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
var size = new Size(random.Next(), random.Next());
|
||||||
|
var point = size.ToPointF();
|
||||||
|
|
||||||
|
Assert.AreEqual(size.Width, point.X, 1e-6f);
|
||||||
|
Assert.AreEqual(size.Height, point.Y, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ToVector2_ShouldReturnVector_WithEquivalentMembers()
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
var point = new Size(random.Next(), random.Next());
|
||||||
|
var size = point.ToVector2();
|
||||||
|
|
||||||
|
Assert.AreEqual(point.Width, size.X, 1e-6f);
|
||||||
|
Assert.AreEqual(point.Height, size.Y, 1e-6f);
|
||||||
|
}
|
||||||
|
}
|
135
X10D.Tests/src/Drawing/SphereTests.cs
Normal file
135
X10D.Tests/src/Drawing/SphereTests.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Drawing;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Drawing;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class SphereTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Circumference_ShouldBe2PiRadius_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
var unitSphere = Sphere.Unit;
|
||||||
|
Assert.AreEqual(2.0f * MathF.PI * unitSphere.Radius, unitSphere.Circumference, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenUnitCircleAndEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, Sphere.Empty.CompareTo(Sphere.Unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenUnitCircleAndEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Sphere.Unit.CompareTo(Sphere.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeNegativeOne_GivenEmptyCircleAndUnitCircleAsObject()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(-1, Sphere.Empty.CompareTo((object)Sphere.Unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeOne_GivenNull()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Sphere.Unit.CompareTo(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldBeZero_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
var unitCircle = Sphere.Unit;
|
||||||
|
Assert.AreEqual(0, unitCircle.CompareTo(unitCircle));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CompareTo_ShouldThrowArgumentException_GivenInvalidType()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => Sphere.Unit.CompareTo(new object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Diameter_ShouldBe2_GivenUnitSphere()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(2.0f, Sphere.Unit.Diameter, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeTrue_GivenTwoUnitCircles()
|
||||||
|
{
|
||||||
|
var unitCircle1 = Sphere.Unit;
|
||||||
|
var unitCircle2 = Sphere.Unit;
|
||||||
|
Assert.AreEqual(unitCircle1, unitCircle2);
|
||||||
|
Assert.IsTrue(unitCircle1 == unitCircle2);
|
||||||
|
Assert.IsFalse(unitCircle1 != unitCircle2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentObjects()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(Sphere.Unit.Equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Equals_ShouldBeFalse_GivenDifferentCircles()
|
||||||
|
{
|
||||||
|
Assert.AreNotEqual(Sphere.Unit, Sphere.Empty);
|
||||||
|
Assert.IsFalse(Sphere.Unit == Sphere.Empty);
|
||||||
|
Assert.IsTrue(Sphere.Unit != Sphere.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenEmptyCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Sphere.Empty.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Sphere.Empty.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetHashCode_ShouldBeCorrect_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
// this test is pretty pointless, it exists only for code coverage purposes
|
||||||
|
int hashCode = Sphere.Unit.GetHashCode();
|
||||||
|
Assert.AreEqual(hashCode, Sphere.Unit.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_GreaterThan_True_GivenUnitAndEmptyCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Sphere.Unit > Sphere.Empty);
|
||||||
|
Assert.IsTrue(Sphere.Unit >= Sphere.Empty);
|
||||||
|
Assert.IsFalse(Sphere.Unit < Sphere.Empty);
|
||||||
|
Assert.IsFalse(Sphere.Unit <= Sphere.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void op_LessThan_True_GivenEmptyAndUnitCircle()
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Sphere.Empty < Sphere.Unit);
|
||||||
|
Assert.IsTrue(Sphere.Empty <= Sphere.Unit);
|
||||||
|
Assert.IsFalse(Sphere.Empty > Sphere.Unit);
|
||||||
|
Assert.IsFalse(Sphere.Empty >= Sphere.Unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Radius_ShouldBe0_GivenEmptySphere()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, Sphere.Empty.Radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Radius_ShouldBe1_GivenUnitSphere()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(1, Sphere.Unit.Radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Volume_ShouldBe4Over3TimesPi_GivenUnitCircle()
|
||||||
|
{
|
||||||
|
var unitSphere = Sphere.Unit;
|
||||||
|
Assert.AreEqual(4.0f / 3.0f * MathF.PI, unitSphere.Volume);
|
||||||
|
}
|
||||||
|
}
|
59
X10D.Tests/src/Hosting/ServiceCollectionTests.cs
Normal file
59
X10D.Tests/src/Hosting/ServiceCollectionTests.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Hosting.DependencyInjection;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Hosting;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class ServiceCollectionTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void AddHostedSingleton_ShouldRegisterServiceAsSingletonAndAsHostedService()
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
|
services.AddHostedSingleton<TestService>();
|
||||||
|
|
||||||
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
|
var service = serviceProvider.GetService<TestService>();
|
||||||
|
var hostedService = serviceProvider.GetService<IHostedService>();
|
||||||
|
|
||||||
|
Assert.IsNotNull(service);
|
||||||
|
Assert.IsNotNull(hostedService);
|
||||||
|
Assert.IsInstanceOfType(service, typeof(TestService));
|
||||||
|
Assert.IsInstanceOfType(hostedService, typeof(TestService));
|
||||||
|
Assert.AreSame(service, hostedService);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddHostedSingleton_ShouldRegisterServiceTypeAsSingletonAndAsHostedService()
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
|
services.AddHostedSingleton(typeof(TestService));
|
||||||
|
|
||||||
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
|
var service = serviceProvider.GetService<TestService>();
|
||||||
|
var hostedService = serviceProvider.GetService<IHostedService>();
|
||||||
|
|
||||||
|
Assert.IsNotNull(service);
|
||||||
|
Assert.IsNotNull(hostedService);
|
||||||
|
Assert.IsInstanceOfType(service, typeof(TestService));
|
||||||
|
Assert.IsInstanceOfType(hostedService, typeof(TestService));
|
||||||
|
Assert.AreSame(service, hostedService);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class TestService : IHostedService
|
||||||
|
{
|
||||||
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
X10D.Tests/src/IO/DirectoryInfoTests.cs
Normal file
57
X10D.Tests/src/IO/DirectoryInfoTests.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class DirectoryInfoTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void Clear_ShouldClear_GivenValidDirectory()
|
||||||
|
{
|
||||||
|
string tempDirectoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||||
|
var tempDirectory = new DirectoryInfo(tempDirectoryPath);
|
||||||
|
|
||||||
|
tempDirectory.Create();
|
||||||
|
Assert.IsTrue(tempDirectory.Exists);
|
||||||
|
|
||||||
|
var file = new FileInfo(Path.Combine(tempDirectory.FullName, "file"));
|
||||||
|
file.Create().Close();
|
||||||
|
|
||||||
|
var childDirectory = new DirectoryInfo(Path.Combine(tempDirectory.FullName, "child"));
|
||||||
|
childDirectory.Create();
|
||||||
|
|
||||||
|
var childFile = new FileInfo(Path.Combine(childDirectory.FullName, "childFile"));
|
||||||
|
childFile.Create().Close();
|
||||||
|
|
||||||
|
Assert.AreEqual(1, tempDirectory.GetFiles().Length);
|
||||||
|
Assert.AreEqual(1, tempDirectory.GetDirectories().Length);
|
||||||
|
tempDirectory.Clear();
|
||||||
|
Assert.AreEqual(0, tempDirectory.GetFiles().Length);
|
||||||
|
Assert.AreEqual(0, tempDirectory.GetDirectories().Length);
|
||||||
|
Assert.IsTrue(tempDirectory.Exists);
|
||||||
|
|
||||||
|
tempDirectory.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Clear_ShouldThrowArgumentNullException_GivenNull()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((DirectoryInfo?)null)!.Clear());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Clear_ShouldThrowDirectoryNotFoundException_GivenInvalidDirectory()
|
||||||
|
{
|
||||||
|
var directory = new DirectoryInfo(@"123:/@12#3");
|
||||||
|
Assert.ThrowsException<DirectoryNotFoundException>(() => directory.Clear());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Clear_ShouldThrowDirectoryNotFoundException_GivenNonExistentDirectory()
|
||||||
|
{
|
||||||
|
var directory = new DirectoryInfo(@"/@12#3");
|
||||||
|
Assert.IsFalse(directory.Exists);
|
||||||
|
Assert.ThrowsException<DirectoryNotFoundException>(() => directory.Clear());
|
||||||
|
}
|
||||||
|
}
|
73
X10D.Tests/src/IO/StreamTests.ReadDecimal.cs
Normal file
73
X10D.Tests/src/IO/StreamTests.ReadDecimal.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDecimal_ShouldThrowArgumentException_GivenNonReadableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadDecimal());
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadDecimal(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadDecimal(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDecimal_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadDecimal());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadDecimal(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadDecimal(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDecimal_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.ReadDecimal((Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDecimal_ShouldReadBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[]
|
||||||
|
{
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x68
|
||||||
|
};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const decimal expected = 420.0m;
|
||||||
|
decimal actual = stream.ReadDecimal(Endianness.BigEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(16, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDecimal_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[]
|
||||||
|
{
|
||||||
|
0x68, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
|
||||||
|
};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const decimal expected = 420.0m;
|
||||||
|
decimal actual = stream.ReadDecimal(Endianness.LittleEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(16, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
67
X10D.Tests/src/IO/StreamTests.ReadDouble.cs
Normal file
67
X10D.Tests/src/IO/StreamTests.ReadDouble.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDouble_ShouldThrowArgumentException_GivenNonReadableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadDouble());
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadDouble(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadDouble(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDouble_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadDouble());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadDouble(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadDouble(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDouble_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.ReadDouble((Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDouble_ShouldReadBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x40, 0x7A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const double expected = 420.0;
|
||||||
|
double actual = stream.ReadDouble(Endianness.BigEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadDouble_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x40};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const double expected = 420.0;
|
||||||
|
double actual = stream.ReadDouble(Endianness.LittleEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
67
X10D.Tests/src/IO/StreamTests.ReadInt16.cs
Normal file
67
X10D.Tests/src/IO/StreamTests.ReadInt16.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt16_ShouldThrowArgumentException_GivenNonReadableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadInt16());
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadInt16(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadInt16(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt16_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadInt16());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadInt16(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadInt16(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt16_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.ReadInt16((Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt16_ShouldReadBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x01, 0xA4};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const short expected = 420;
|
||||||
|
short actual = stream.ReadInt16(Endianness.BigEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt16_ShouldReadLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0xA4, 0x01};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const short expected = 420;
|
||||||
|
short actual = stream.ReadInt16(Endianness.LittleEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
67
X10D.Tests/src/IO/StreamTests.ReadInt32.cs
Normal file
67
X10D.Tests/src/IO/StreamTests.ReadInt32.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt32_ShouldThrowArgumentException_GivenNonReadableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadInt32());
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadInt32(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadInt32(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt32_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadInt32());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadInt32(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadInt32(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt32_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.ReadInt32((Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt32_ShouldReadBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x00, 0x00, 0x01, 0xA4};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const int expected = 420;
|
||||||
|
int actual = stream.ReadInt32(Endianness.BigEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt32_ShouldReadLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0xA4, 0x01, 0x00, 0x00};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const int expected = 420;
|
||||||
|
int actual = stream.ReadInt32(Endianness.LittleEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
67
X10D.Tests/src/IO/StreamTests.ReadInt64.cs
Normal file
67
X10D.Tests/src/IO/StreamTests.ReadInt64.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt64_ShouldThrowArgumentException_GivenNonReadableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadInt64());
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadInt64(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadInt64(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt64_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadInt64());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadInt64(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadInt64(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt64_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.ReadInt64((Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt64_ShouldReadBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA4};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const long expected = 420;
|
||||||
|
long actual = stream.ReadInt64(Endianness.BigEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadInt64_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0xA4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const long expected = 420;
|
||||||
|
long actual = stream.ReadInt64(Endianness.LittleEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
67
X10D.Tests/src/IO/StreamTests.ReadSingle.cs
Normal file
67
X10D.Tests/src/IO/StreamTests.ReadSingle.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadSingle_ShouldThrowArgumentException_GivenNonReadableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadSingle());
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadSingle(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadSingle(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadSingle_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadSingle());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadSingle(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadSingle(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadSingle_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.ReadSingle((Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadSingle_ShouldReadBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x43, 0xD2, 0x00, 0x00};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const float expected = 420.0f;
|
||||||
|
float actual = stream.ReadSingle(Endianness.BigEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReadSingle_ShouldReadLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x00, 0x00, 0xD2, 0x43};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const float expected = 420.0f;
|
||||||
|
float actual = stream.ReadSingle(Endianness.LittleEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
72
X10D.Tests/src/IO/StreamTests.ReadUInt16.cs
Normal file
72
X10D.Tests/src/IO/StreamTests.ReadUInt16.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt16_ShouldThrowArgumentException_GivenNonReadableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadUInt16());
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadUInt16(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadUInt16(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt16_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadUInt16());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadUInt16(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadUInt16(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt16_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.ReadUInt16((Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt16_ShouldReadBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x01, 0xA4};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const ushort expected = 420;
|
||||||
|
ushort actual = stream.ReadUInt16(Endianness.BigEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt16_ShouldReadLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0xA4, 0x01};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const ushort expected = 420;
|
||||||
|
ushort actual = stream.ReadUInt16(Endianness.LittleEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
72
X10D.Tests/src/IO/StreamTests.ReadUInt32.cs
Normal file
72
X10D.Tests/src/IO/StreamTests.ReadUInt32.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt32_ShouldThrowArgumentException_GivenNonReadableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadUInt32());
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadUInt32(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadUInt32(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt32_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadUInt32());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadUInt32(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadUInt32(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt32_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.ReadUInt32((Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt32_ShouldReadBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x00, 0x00, 0x01, 0xA4};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const uint expected = 420;
|
||||||
|
uint actual = stream.ReadUInt32(Endianness.BigEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt32_ShouldReadLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0xA4, 0x01, 0x00, 0x00};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const uint expected = 420;
|
||||||
|
uint actual = stream.ReadUInt32(Endianness.LittleEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
72
X10D.Tests/src/IO/StreamTests.ReadUInt64.cs
Normal file
72
X10D.Tests/src/IO/StreamTests.ReadUInt64.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt64_ShouldThrowArgumentException_GivenNonReadableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadUInt64());
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadUInt64(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.ReadUInt64(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt64_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadUInt64());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadUInt64(Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.ReadUInt64(Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt64_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.ReadUInt64((Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt64_ShouldReadBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA4};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const ulong expected = 420;
|
||||||
|
ulong actual = stream.ReadUInt64(Endianness.BigEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void ReadUInt64_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
ReadOnlySpan<byte> bytes = stackalloc byte[] {0xA4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
stream.Write(bytes);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
const ulong expected = 420;
|
||||||
|
ulong actual = stream.ReadUInt64(Endianness.LittleEndian);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
77
X10D.Tests/src/IO/StreamTests.WriteDecimal.cs
Normal file
77
X10D.Tests/src/IO/StreamTests.WriteDecimal.cs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDecimal_ShouldThrowArgumentException_GivenNonWriteableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420.0m, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420.0m, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDecimal_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420.0m, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420.0m, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDecimal_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420.0m, (Endianness)(-1)));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420.0m, (Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDecimal_ShouldWriteBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420.0m, Endianness.BigEndian);
|
||||||
|
Assert.AreEqual(16, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[16];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[]
|
||||||
|
{
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x68
|
||||||
|
};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(16, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDecimal_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420.0m, Endianness.LittleEndian);
|
||||||
|
Assert.AreEqual(16, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[16];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[]
|
||||||
|
{
|
||||||
|
0x68, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
|
||||||
|
};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Trace.WriteLine(string.Join(", ", actual.ToArray().Select(b => $"0x{b:X2}")));
|
||||||
|
|
||||||
|
Assert.AreEqual(16, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
}
|
68
X10D.Tests/src/IO/StreamTests.WriteDouble.cs
Normal file
68
X10D.Tests/src/IO/StreamTests.WriteDouble.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDouble_ShouldThrowArgumentException_GivenNonWriteableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420.0, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420.0, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDouble_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420.0, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420.0, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDouble_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420.0, (Endianness)(-1)));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420.0, (Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDouble_ShouldWriteBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420.0, Endianness.BigEndian);
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[8];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x40, 0x7A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteDouble_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420.0, Endianness.LittleEndian);
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[8];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x40};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
}
|
68
X10D.Tests/src/IO/StreamTests.WriteInt16.cs
Normal file
68
X10D.Tests/src/IO/StreamTests.WriteInt16.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt16_ShouldThrowArgumentException_GivenNonWriteableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write((short)420, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write((short)420, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt16_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write((short)420, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write((short)420, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt16_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write((short)420, (Endianness)(-1)));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write((short)420, (Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt16_ShouldWriteBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write((short)420, Endianness.BigEndian);
|
||||||
|
Assert.AreEqual(2, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[2];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x01, 0xA4};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt16_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write((short)420, Endianness.LittleEndian);
|
||||||
|
Assert.AreEqual(2, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[2];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0xA4, 0x01};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
}
|
68
X10D.Tests/src/IO/StreamTests.WriteInt32.cs
Normal file
68
X10D.Tests/src/IO/StreamTests.WriteInt32.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt32_ShouldThrowArgumentException_GivenNonWriteableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt32_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt32_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420, (Endianness)(-1)));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420, (Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt32_ShouldWriteBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420, Endianness.BigEndian);
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[4];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x00, 0x00, 0x01, 0xA4};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt32_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420, Endianness.LittleEndian);
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[4];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0xA4, 0x01, 0x00, 0x00};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
}
|
68
X10D.Tests/src/IO/StreamTests.WriteInt64.cs
Normal file
68
X10D.Tests/src/IO/StreamTests.WriteInt64.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt64_ShouldThrowArgumentException_GivenNonWriteableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420L, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420L, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt64_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420L, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420L, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt64_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420L, (Endianness)(-1)));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420L, (Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt64_ShouldWriteBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420L, Endianness.BigEndian);
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[8];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA4};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteInt64_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420L, Endianness.LittleEndian);
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[8];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0xA4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
}
|
68
X10D.Tests/src/IO/StreamTests.WriteSingle.cs
Normal file
68
X10D.Tests/src/IO/StreamTests.WriteSingle.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteSingle_ShouldThrowArgumentException_GivenNonWriteableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420.0f, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420.0f, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteSingle_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420.0f, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420.0f, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteSingle_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420.0f, (Endianness)(-1)));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420.0f, (Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteSingle_ShouldWriteBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420.0f, Endianness.BigEndian);
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[4];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x43, 0xD2, 0x00, 0x00};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WriteSingle_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420.0f, Endianness.LittleEndian);
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[4];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x00, 0x00, 0xD2, 0x43};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
}
|
73
X10D.Tests/src/IO/StreamTests.WriteUInt16.cs
Normal file
73
X10D.Tests/src/IO/StreamTests.WriteUInt16.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt16_ShouldThrowArgumentException_GivenNonWriteableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write((ushort)420, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write((ushort)420, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt16_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write((ushort)420, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write((ushort)420, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt16_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write((ushort)420, (Endianness)(-1)));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write((ushort)420, (Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt16_ShouldWriteBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write((ushort)420, Endianness.BigEndian);
|
||||||
|
Assert.AreEqual(2, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[2];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x01, 0xA4};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt16_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write((ushort)420, Endianness.LittleEndian);
|
||||||
|
Assert.AreEqual(2, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[2];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0xA4, 0x01};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
}
|
73
X10D.Tests/src/IO/StreamTests.WriteUInt32.cs
Normal file
73
X10D.Tests/src/IO/StreamTests.WriteUInt32.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt32_ShouldThrowArgumentException_GivenNonWriteableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420U, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420U, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt32_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420U, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420U, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt32_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420U, (Endianness)(-1)));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420U, (Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt32_ShouldWriteBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420U, Endianness.BigEndian);
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[4];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x00, 0x00, 0x01, 0xA4};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt32_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420U, Endianness.LittleEndian);
|
||||||
|
Assert.AreEqual(4, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[4];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0xA4, 0x01, 0x00, 0x00};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
}
|
73
X10D.Tests/src/IO/StreamTests.WriteUInt64.cs
Normal file
73
X10D.Tests/src/IO/StreamTests.WriteUInt64.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
public partial class StreamTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt64_ShouldThrowArgumentException_GivenNonWriteableStream()
|
||||||
|
{
|
||||||
|
Stream stream = new DummyStream();
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420UL, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentException>(() => stream.Write(420UL, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt64_ShouldThrowArgumentNullException_GivenNullStream()
|
||||||
|
{
|
||||||
|
Stream stream = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420UL, Endianness.LittleEndian));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => stream.Write(420UL, Endianness.BigEndian));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt64_ShouldThrowArgumentOutOfRangeException_GivenInvalidEndiannessValue()
|
||||||
|
{
|
||||||
|
// we don't need to enclose this stream in a using declaration, since disposing a
|
||||||
|
// null stream is meaningless. NullStream.Dispose actually does nothing, anyway.
|
||||||
|
// that - coupled with the fact that encapsulating the stream in a using declaration causes the
|
||||||
|
// analyser to trip up and think the stream is disposed by the time the local is captured in
|
||||||
|
// assertion lambda - means this line is fine as it is. please do not change.
|
||||||
|
Stream stream = Stream.Null;
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420UL, (Endianness)(-1)));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => stream.Write(420UL, (Endianness)(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt64_ShouldWriteBigEndian_GivenBigEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420UL, Endianness.BigEndian);
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[8];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA4};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public void WriteUInt64_ShouldWriteLittleEndian_GivenLittleEndian()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
stream.Write(420UL, Endianness.LittleEndian);
|
||||||
|
Assert.AreEqual(8, stream.Position);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
Span<byte> actual = stackalloc byte[8];
|
||||||
|
ReadOnlySpan<byte> expected = stackalloc byte[] {0xA4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
int read = stream.Read(actual);
|
||||||
|
|
||||||
|
Assert.AreEqual(8, read);
|
||||||
|
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ using X10D.IO;
|
|||||||
namespace X10D.Tests.IO;
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class StreamTests
|
public partial class StreamTests
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void GetHashSha1ShouldBeCorrect()
|
public void GetHashSha1ShouldBeCorrect()
|
||||||
@ -99,341 +99,6 @@ public class StreamTests
|
|||||||
Stream.Null.TryWriteHash<HashAlgorithmTestClassNoCreateMethod>(Span<byte>.Empty, out _));
|
Stream.Null.TryWriteHash<HashAlgorithmTestClassNoCreateMethod>(Span<byte>.Empty, out _));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void Write_ShouldThrow_GivenUndefinedEndianness()
|
|
||||||
{
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.Write(0.0f, (Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.Write(0.0, (Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.Write(0.0m, (Endianness)(-1));
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.Write((short)0, (Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.Write(0, (Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.Write(0L, (Endianness)(-1));
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.Write((ushort)0, (Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.Write(0U, (Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.Write(0UL, (Endianness)(-1));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void Read_ShouldThrow_GivenNullStream()
|
|
||||||
{
|
|
||||||
Stream? stream = null;
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.ReadSingle());
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.ReadDouble());
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.ReadDecimal());
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.ReadInt16());
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.ReadInt32());
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.ReadInt64());
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.ReadUInt16());
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.ReadUInt32());
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.ReadUInt64());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void Write_ShouldThrow_GivenNullStream()
|
|
||||||
{
|
|
||||||
Stream? stream = null;
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.Write(0.0f, Endianness.LittleEndian));
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.Write(0.0, Endianness.LittleEndian));
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.Write(0.0m, Endianness.LittleEndian));
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.Write((short)0));
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.Write(0));
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.Write(0L));
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.Write((ushort)0));
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.Write(0U));
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => stream!.Write(0UL));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void Read_ShouldThrow_GivenUndefinedEndianness()
|
|
||||||
{
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.ReadSingle((Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.ReadDouble((Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.ReadDecimal((Endianness)(-1));
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.ReadInt16((Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.ReadInt32((Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.ReadInt64((Endianness)(-1));
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.ReadUInt16((Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.ReadUInt32((Endianness)(-1));
|
|
||||||
});
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
return stream.ReadUInt64((Endianness)(-1));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ReadDouble_WriteDouble_ShouldBeSymmetric()
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write(420.0, BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420.0, stream.ReadDouble(), 1e-6);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420.0, Endianness.LittleEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420.0, stream.ReadDouble(Endianness.LittleEndian), 1e-6);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420.0, Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420.0, stream.ReadDouble(Endianness.BigEndian), 1e-6);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ReadDecimal_WriteSingle_ShouldBeSymmetric()
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write(420.0m, BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420.0m, stream.ReadDecimal());
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420.0m, Endianness.LittleEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420.0m, stream.ReadDecimal(Endianness.LittleEndian));
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420.0m, Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420.0m, stream.ReadDecimal(Endianness.BigEndian));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ReadSingle_WriteSingle_ShouldBeSymmetric()
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write(420.0f, BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420.0f, stream.ReadSingle(), 1e-6f);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420.0f, Endianness.LittleEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420.0f, stream.ReadSingle(Endianness.LittleEndian), 1e-6f);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420.0f, Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420.0f, stream.ReadSingle(Endianness.BigEndian), 1e-6f);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ReadInt16_WriteInt16_ShouldBeSymmetric()
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write((short)420);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420, stream.ReadInt16());
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write((short)420, Endianness.LittleEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420, stream.ReadInt16(Endianness.LittleEndian));
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write((short)420, Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420, stream.ReadInt16(Endianness.BigEndian));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ReadInt32_WriteInt32_ShouldBeSymmetric()
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write(420);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420, stream.ReadInt32());
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420, Endianness.LittleEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420, stream.ReadInt32(Endianness.LittleEndian));
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420, Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420, stream.ReadInt32(Endianness.BigEndian));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ReadInt64_WriteInt64_ShouldBeSymmetric()
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write(420L);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420L, stream.ReadInt64());
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420L, Endianness.LittleEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420L, stream.ReadInt64(Endianness.LittleEndian));
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420L, Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420L, stream.ReadInt64(Endianness.BigEndian));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[CLSCompliant(false)]
|
|
||||||
public void ReadUInt16_WriteUInt16_ShouldBeSymmetric()
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write((ushort)420);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual((ushort)420, stream.ReadUInt16());
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write((ushort)420, Endianness.LittleEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual((ushort)420, stream.ReadUInt16(Endianness.LittleEndian));
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write((ushort)420, Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual((ushort)420, stream.ReadUInt16(Endianness.BigEndian));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[CLSCompliant(false)]
|
|
||||||
public void ReadUInt32_WriteUInt32_ShouldBeSymmetric()
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write(420U);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420U, stream.ReadUInt32());
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420U, Endianness.LittleEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420U, stream.ReadUInt32(Endianness.LittleEndian));
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420U, Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420U, stream.ReadUInt32(Endianness.BigEndian));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[CLSCompliant(false)]
|
|
||||||
public void ReadUInt64_WriteUInt64_ShouldBeSymmetric()
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write(420UL);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420UL, stream.ReadUInt64());
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420UL, Endianness.LittleEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420UL, stream.ReadUInt64(Endianness.LittleEndian));
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
stream.Write(420UL, Endianness.BigEndian);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
Assert.AreEqual(420UL, stream.ReadUInt64(Endianness.BigEndian));
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DummyStream : Stream
|
private class DummyStream : Stream
|
||||||
{
|
{
|
||||||
public DummyStream(bool readable = false)
|
public DummyStream(bool readable = false)
|
||||||
@ -492,17 +157,15 @@ public class StreamTests
|
|||||||
|
|
||||||
protected override void HashCore(byte[] array, int ibStart, int cbSize)
|
protected override void HashCore(byte[] array, int ibStart, int cbSize)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override byte[] HashFinal()
|
protected override byte[] HashFinal()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return Array.Empty<byte>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,17 +173,15 @@ public class StreamTests
|
|||||||
{
|
{
|
||||||
protected override void HashCore(byte[] array, int ibStart, int cbSize)
|
protected override void HashCore(byte[] array, int ibStart, int cbSize)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override byte[] HashFinal()
|
protected override byte[] HashFinal()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return Array.Empty<byte>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
83
X10D.Tests/src/IO/TextReaderTests.cs
Normal file
83
X10D.Tests/src/IO/TextReaderTests.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.IO;
|
||||||
|
|
||||||
|
namespace X10D.Tests.IO;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class TextReaderTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void EnumerateLines_ShouldYield10Lines_Given10LineString()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
using (var writer = new StreamWriter(stream, Encoding.UTF8, leaveOpen: true))
|
||||||
|
{
|
||||||
|
for (var index = 0; index < 10; index++)
|
||||||
|
{
|
||||||
|
writer.WriteLine(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.Position = 0;
|
||||||
|
using var reader = new StreamReader(stream, Encoding.UTF8);
|
||||||
|
var lineCount = 0;
|
||||||
|
|
||||||
|
foreach (string _ in reader.EnumerateLines())
|
||||||
|
{
|
||||||
|
lineCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(10, lineCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task EnumerateLinesAsync_ShouldYield10Lines_Given10LineString()
|
||||||
|
{
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
await using (var writer = new StreamWriter(stream, Encoding.UTF8, leaveOpen: true))
|
||||||
|
{
|
||||||
|
for (var index = 0; index < 10; index++)
|
||||||
|
{
|
||||||
|
writer.WriteLine(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.Position = 0;
|
||||||
|
using var reader = new StreamReader(stream, Encoding.UTF8);
|
||||||
|
var lineCount = 0;
|
||||||
|
|
||||||
|
await foreach (string _ in reader.EnumerateLinesAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
lineCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(10, lineCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void EnumerateLines_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
TextReader reader = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() =>
|
||||||
|
{
|
||||||
|
foreach (string _ in reader.EnumerateLines())
|
||||||
|
{
|
||||||
|
// loop body is intentionally empty
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task EnumerateLinesAsync_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
TextReader reader = null!;
|
||||||
|
await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await foreach (string _ in reader.EnumerateLinesAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
// loop body is intentionally empty
|
||||||
|
}
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,14 @@ public class ByteTests
|
|||||||
// Π_(i=1)^n (2i) will overflow at i=4 for byte
|
// Π_(i=1)^n (2i) will overflow at i=4 for byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<byte> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void RangeTo_Byte_ShouldYieldCorrectValues()
|
public void RangeTo_Byte_ShouldYieldCorrectValues()
|
||||||
{
|
{
|
||||||
|
@ -41,4 +41,12 @@ public class DecimalTests
|
|||||||
Assert.AreEqual(185794560m, Enumerable.Range(1, 9).Product(Double));
|
Assert.AreEqual(185794560m, Enumerable.Range(1, 9).Product(Double));
|
||||||
Assert.AreEqual(3715891200m, Enumerable.Range(1, 10).Product(Double));
|
Assert.AreEqual(3715891200m, Enumerable.Range(1, 10).Product(Double));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<decimal> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,4 +41,12 @@ public class DoubleTests
|
|||||||
Assert.AreEqual(185794560.0, Enumerable.Range(1, 9).Product(Double));
|
Assert.AreEqual(185794560.0, Enumerable.Range(1, 9).Product(Double));
|
||||||
Assert.AreEqual(3715891200.0, Enumerable.Range(1, 10).Product(Double));
|
Assert.AreEqual(3715891200.0, Enumerable.Range(1, 10).Product(Double));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<double> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
239
X10D.Tests/src/Linq/EnumerableTests.cs
Normal file
239
X10D.Tests/src/Linq/EnumerableTests.cs
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Linq;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Linq;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class EnumerableTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ConcatOne_ShouldReturnConcatenatedSequence_GivenValidSequenceAndValue()
|
||||||
|
{
|
||||||
|
IEnumerable<string> source = new[] {"Hello"};
|
||||||
|
string[] expected = {"Hello", "World"};
|
||||||
|
|
||||||
|
string[] actual = source.ConcatOne("World").ToArray();
|
||||||
|
|
||||||
|
Assert.AreEqual(2, actual.Length);
|
||||||
|
CollectionAssert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ConcatOne_ShouldReturnSingletonSequence_GivenEmptySequenceAndValidValue()
|
||||||
|
{
|
||||||
|
IEnumerable<string> source = Enumerable.Empty<string>();
|
||||||
|
string[] expected = {"Foobar"};
|
||||||
|
|
||||||
|
string[] actual = source.ConcatOne("Foobar").ToArray();
|
||||||
|
|
||||||
|
Assert.AreEqual(1, actual.Length);
|
||||||
|
CollectionAssert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ConcatOne_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<string>? source = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source!.ConcatOne("Foobar").ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMax_ShouldReturnCorrectValues_UsingDefaultComparer()
|
||||||
|
{
|
||||||
|
IEnumerable<int> source = Enumerable.Range(1, 10);
|
||||||
|
(int minimum, int maximum) = source.MinMax();
|
||||||
|
Assert.AreEqual(1, minimum);
|
||||||
|
Assert.AreEqual(10, maximum);
|
||||||
|
|
||||||
|
source = Enumerable.Range(1, 10).ToArray();
|
||||||
|
(minimum, maximum) = source.MinMax();
|
||||||
|
Assert.AreEqual(1, minimum);
|
||||||
|
Assert.AreEqual(10, maximum);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMax_ShouldReturnCorrectSelectedValues_UsingDefaultComparer()
|
||||||
|
{
|
||||||
|
IEnumerable<Person> source = Enumerable.Range(1, 10).Select(i => new Person {Age = i});
|
||||||
|
(int minimum, int maximum) = source.MinMax(p => p.Age);
|
||||||
|
Assert.AreEqual(1, minimum);
|
||||||
|
Assert.AreEqual(10, maximum);
|
||||||
|
|
||||||
|
source = Enumerable.Range(1, 10).Select(i => new Person {Age = i}).ToArray();
|
||||||
|
(minimum, maximum) = source.MinMax(p => p.Age);
|
||||||
|
Assert.AreEqual(1, minimum);
|
||||||
|
Assert.AreEqual(10, maximum);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMax_ShouldReturnOppositeSelectedValues_UsingInverseComparer()
|
||||||
|
{
|
||||||
|
IEnumerable<Person> source = Enumerable.Range(1, 10).Select(i => new Person {Age = i});
|
||||||
|
(int minimum, int maximum) = source.MinMax(p => p.Age, new InverseComparer<int>());
|
||||||
|
Assert.AreEqual(10, minimum);
|
||||||
|
Assert.AreEqual(1, maximum);
|
||||||
|
|
||||||
|
source = Enumerable.Range(1, 10).Select(i => new Person {Age = i}).ToArray();
|
||||||
|
(minimum, maximum) = source.MinMax(p => p.Age, new InverseComparer<int>());
|
||||||
|
Assert.AreEqual(10, minimum);
|
||||||
|
Assert.AreEqual(1, maximum);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMax_ShouldReturnOppositeValues_UsingInverseComparer()
|
||||||
|
{
|
||||||
|
(int minimum, int maximum) = Enumerable.Range(1, 10).MinMax(new InverseComparer<int>());
|
||||||
|
Assert.AreEqual(10, minimum);
|
||||||
|
Assert.AreEqual(1, maximum);
|
||||||
|
|
||||||
|
(minimum, maximum) = Enumerable.Range(1, 10).ToArray().MinMax(new InverseComparer<int>());
|
||||||
|
Assert.AreEqual(10, minimum);
|
||||||
|
Assert.AreEqual(1, maximum);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMax_ShouldThrowArgumentNullException_GivenNullSelector()
|
||||||
|
{
|
||||||
|
IEnumerable<int> source = Enumerable.Empty<int>();
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.MinMax((Func<int, int>)(null!)));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.MinMax((Func<int, int>)(null!), null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMax_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<int>? source = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source!.MinMax());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source!.MinMax(v => v));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source!.MinMax(null));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source!.MinMax(v => v, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMax_ShouldThrowInvalidOperationException_GivenEmptySource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => Enumerable.Empty<int>().MinMax());
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => Array.Empty<int>().MinMax());
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => new List<int>().MinMax());
|
||||||
|
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => Enumerable.Empty<int>().MinMax(i => i * 2));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => Array.Empty<int>().MinMax(i => i * 2));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => new List<int>().MinMax(i => i * 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxBy_ShouldReturnCorrectSelectedValues_UsingDefaultComparer()
|
||||||
|
{
|
||||||
|
IEnumerable<Person> source = Enumerable.Range(1, 10).Select(i => new Person {Age = i});
|
||||||
|
(Person minimum, Person maximum) = source.MinMaxBy(p => p.Age);
|
||||||
|
Assert.AreEqual(1, minimum.Age);
|
||||||
|
Assert.AreEqual(10, maximum.Age);
|
||||||
|
|
||||||
|
source = Enumerable.Range(1, 10).Select(i => new Person {Age = i}).ToArray();
|
||||||
|
(minimum, maximum) = source.MinMaxBy(p => p.Age);
|
||||||
|
Assert.AreEqual(1, minimum.Age);
|
||||||
|
Assert.AreEqual(10, maximum.Age);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxBy_ShouldReturnOppositeSelectedValues_UsingInverseComparer()
|
||||||
|
{
|
||||||
|
IEnumerable<Person> source = Enumerable.Range(1, 10).Select(i => new Person {Age = i});
|
||||||
|
(Person minimum, Person maximum) = source.MinMaxBy(p => p.Age, new InverseComparer<int>());
|
||||||
|
Assert.AreEqual(10, minimum.Age);
|
||||||
|
Assert.AreEqual(1, maximum.Age);
|
||||||
|
|
||||||
|
source = Enumerable.Range(1, 10).Select(i => new Person {Age = i}).ToArray();
|
||||||
|
(minimum, maximum) = source.MinMaxBy(p => p.Age, new InverseComparer<int>());
|
||||||
|
Assert.AreEqual(10, minimum.Age);
|
||||||
|
Assert.AreEqual(1, maximum.Age);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxBy_ShouldThrowArgumentNullException_GivenNullSelector()
|
||||||
|
{
|
||||||
|
Person[] source = Enumerable.Range(1, 10).Select(i => new Person {Age = i}).ToArray();
|
||||||
|
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.MinMaxBy((Func<Person, int>)null!));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.MinMaxBy((Func<Person, int>)null!, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxBy_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<Person>? source = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source!.MinMaxBy(p => p.Age));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source!.MinMaxBy(p => p.Age, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxBy_ShouldThrowInvalidOperationException_GivenEmptySource()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
IEnumerable<Person> source = Enumerable.Empty<Person>();
|
||||||
|
return source.MinMaxBy(p => p.Age);
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
Person[] source = Array.Empty<Person>();
|
||||||
|
return source.MinMaxBy(p => p.Age);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct InverseComparer<T> : IComparer<T> where T : IComparable<T>
|
||||||
|
{
|
||||||
|
public int Compare(T? x, T? y)
|
||||||
|
{
|
||||||
|
if (x is null)
|
||||||
|
{
|
||||||
|
return y is null ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return y is null ? -1 : y.CompareTo(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct Person : IComparable<Person>, IComparable
|
||||||
|
{
|
||||||
|
public int Age { get; set; }
|
||||||
|
|
||||||
|
public static bool operator <(Person left, Person right)
|
||||||
|
{
|
||||||
|
return left.CompareTo(right) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator >(Person left, Person right)
|
||||||
|
{
|
||||||
|
return left.CompareTo(right) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator <=(Person left, Person right)
|
||||||
|
{
|
||||||
|
return left.CompareTo(right) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator >=(Person left, Person right)
|
||||||
|
{
|
||||||
|
return left.CompareTo(right) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Person other)
|
||||||
|
{
|
||||||
|
return Age.CompareTo(other.Age);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(object? obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is Person other
|
||||||
|
? CompareTo(other)
|
||||||
|
: throw new ArgumentException(ExceptionMessages.ObjectIsNotAValidType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,13 @@ public class Int16Tests
|
|||||||
// Π_(i=1)^n (2i) will overflow at i=6 for short
|
// Π_(i=1)^n (2i) will overflow at i=6 for short
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<short> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void RangeTo_Int16_ShouldYieldCorrectValues()
|
public void RangeTo_Int16_ShouldYieldCorrectValues()
|
||||||
{
|
{
|
||||||
|
@ -41,6 +41,14 @@ public class Int32Tests
|
|||||||
// Π_(i=1)^n (2i) will overflow at i=10 for int
|
// Π_(i=1)^n (2i) will overflow at i=10 for int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<int> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void RangeTo_Int32_ShouldYieldCorrectValues()
|
public void RangeTo_Int32_ShouldYieldCorrectValues()
|
||||||
{
|
{
|
||||||
|
@ -42,6 +42,14 @@ public class Int64Tests
|
|||||||
Assert.AreEqual(3715891200, Enumerable.Range(1, 10).Product(Double));
|
Assert.AreEqual(3715891200, Enumerable.Range(1, 10).Product(Double));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<long> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void RangeTo_Int64_ShouldYieldCorrectValues()
|
public void RangeTo_Int64_ShouldYieldCorrectValues()
|
||||||
{
|
{
|
||||||
|
@ -34,4 +34,12 @@ public class SByteTests
|
|||||||
|
|
||||||
// Π_(i=1)^(n(i*2)) will overflow at i=4 for sbyte
|
// Π_(i=1)^(n(i*2)) will overflow at i=4 for sbyte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<sbyte> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,4 +41,12 @@ public class SingleTests
|
|||||||
Assert.AreEqual(185794560f, Enumerable.Range(1, 9).Product(Double));
|
Assert.AreEqual(185794560f, Enumerable.Range(1, 9).Product(Double));
|
||||||
Assert.AreEqual(3715891200f, Enumerable.Range(1, 10).Product(Double));
|
Assert.AreEqual(3715891200f, Enumerable.Range(1, 10).Product(Double));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<float> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,4 +40,12 @@ public class UInt16Tests
|
|||||||
|
|
||||||
// Π_(i=1)^n (2i) will overflow at i=7 for ushort
|
// Π_(i=1)^n (2i) will overflow at i=7 for ushort
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<ushort> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,4 +42,12 @@ public class UInt32Tests
|
|||||||
Assert.AreEqual(185794560U, Enumerable.Range(1, 9).Product(Double));
|
Assert.AreEqual(185794560U, Enumerable.Range(1, 9).Product(Double));
|
||||||
Assert.AreEqual(3715891200U, Enumerable.Range(1, 10).Product(Double));
|
Assert.AreEqual(3715891200U, Enumerable.Range(1, 10).Product(Double));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<uint> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,4 +42,12 @@ public class UInt64Tests
|
|||||||
Assert.AreEqual(185794560UL, Enumerable.Range(1, 9).Product(Double));
|
Assert.AreEqual(185794560UL, Enumerable.Range(1, 9).Product(Double));
|
||||||
Assert.AreEqual(3715891200UL, Enumerable.Range(1, 10).Product(Double));
|
Assert.AreEqual(3715891200UL, Enumerable.Range(1, 10).Product(Double));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Product_ShouldThrowArgumentNullException_GivenNullSource()
|
||||||
|
{
|
||||||
|
IEnumerable<ulong> source = null!;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product());
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => source.Product(v => v));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user