diff --git a/.editorconfig b/.editorconfig index 2e3045fb..f579ff5d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -104,8 +104,8 @@ dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:war dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning dotnet_style_parentheses_in_other_operators = always_for_clarity:suggestion # Expression-level preferences -dotnet_style_object_initializer = true:warning -dotnet_style_collection_initializer = true:warning +dotnet_style_object_initializer = true:error +dotnet_style_collection_initializer = true:error dotnet_style_explicit_tuple_names = true:warning dotnet_style_prefer_inferred_tuple_names = true:warning dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning @@ -135,9 +135,9 @@ csharp_style_prefer_null_check_over_type_check = true:warning # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#c-style-rules [*.{cs,csx,cake}] # 'var' preferences -csharp_style_var_for_built_in_types = false:warning -csharp_style_var_when_type_is_apparent = false:warning -csharp_style_var_elsewhere = false:warning +csharp_style_var_for_built_in_types = false:error +csharp_style_var_when_type_is_apparent = false:error +csharp_style_var_elsewhere = false:error # Expression-bodied members csharp_style_expression_bodied_methods = true:warning csharp_style_expression_bodied_constructors = true:warning @@ -160,7 +160,10 @@ csharp_style_pattern_local_over_anonymous_function = true:warning csharp_style_deconstructed_variable_declaration = true:warning csharp_style_prefer_index_operator = true:warning csharp_style_prefer_range_operator = true:warning -csharp_style_implicit_object_creation_when_type_is_apparent = true:warning +csharp_style_implicit_object_creation_when_type_is_apparent = true:error +# ReSharper inspection severities +resharper_arrange_object_creation_when_type_evident_highlighting = error +resharper_arrange_object_creation_when_type_not_evident_highlighting = error # "Null" checking preferences csharp_style_throw_expression = true:warning csharp_style_conditional_delegate_call = true:warning @@ -172,6 +175,11 @@ dotnet_diagnostic.IDE0063.severity = suggestion csharp_using_directive_placement = outside_namespace:warning # Modifier preferences csharp_prefer_static_local_function = true:warning +# Primary constructor preferences +csharp_style_prefer_primary_constructors = false:none +# Collection preferences +dotnet_style_prefer_collection_expression = true:error +resharper_use_collection_expression_highlighting =true:error ########################################## # Unnecessary Code Rules diff --git a/.gitattributes b/.gitattributes index ff4ec940..7de2c159 100644 --- a/.gitattributes +++ b/.gitattributes @@ -85,18 +85,12 @@ ############################################################################### *.basis binary *.dll binary -*.eot binary *.exe binary -*.otf binary *.pdf binary *.ppt binary *.pptx binary *.pvr binary *.snk binary -*.ttc binary -*.ttf binary -*.woff binary -*.woff2 binary *.xls binary *.xlsx binary ############################################################################### @@ -118,6 +112,7 @@ *.bmp filter=lfs diff=lfs merge=lfs -text *.gif filter=lfs diff=lfs merge=lfs -text *.png filter=lfs diff=lfs merge=lfs -text +*.qoi filter=lfs diff=lfs merge=lfs -text *.tif filter=lfs diff=lfs merge=lfs -text *.tiff filter=lfs diff=lfs merge=lfs -text *.tga filter=lfs diff=lfs merge=lfs -text @@ -125,6 +120,7 @@ *.dds filter=lfs diff=lfs merge=lfs -text *.ktx filter=lfs diff=lfs merge=lfs -text *.ktx2 filter=lfs diff=lfs merge=lfs -text +*.astc filter=lfs diff=lfs merge=lfs -text *.pam filter=lfs diff=lfs merge=lfs -text *.pbm filter=lfs diff=lfs merge=lfs -text *.pgm filter=lfs diff=lfs merge=lfs -text @@ -132,3 +128,22 @@ *.pnm filter=lfs diff=lfs merge=lfs -text *.wbmp filter=lfs diff=lfs merge=lfs -text *.exr filter=lfs diff=lfs merge=lfs -text +*.ico filter=lfs diff=lfs merge=lfs -text +*.cur filter=lfs diff=lfs merge=lfs -text +*.ani filter=lfs diff=lfs merge=lfs -text +*.heic filter=lfs diff=lfs merge=lfs -text +*.hif filter=lfs diff=lfs merge=lfs -text +*.avif filter=lfs diff=lfs merge=lfs -text +############################################################################### +# Handle ICC files by git lfs +############################################################################### +*.icc filter=lfs diff=lfs merge=lfs -text +############################################################################### +# Handle font files by git lfs +############################################################################### +*.eot filter=lfs diff=lfs merge=lfs -text +*.otf filter=lfs diff=lfs merge=lfs -text +*.ttc filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.woff filter=lfs diff=lfs merge=lfs -text +*.woff2 filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d323d270..7f4f9078 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -4,42 +4,90 @@ on: push: branches: - main + - release/* tags: - "v*" pull_request: branches: - main + - release/* + types: [ opened, synchronize, reopened ] jobs: + # Prime a single LFS cache and expose the exact key for the matrix + WarmLFS: + runs-on: ubuntu-latest + outputs: + lfs_key: ${{ steps.expose-key.outputs.lfs_key }} + steps: + - name: Git Config + shell: bash + run: | + git config --global core.autocrlf false + git config --global core.longpaths true + + - name: Git Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + submodules: recursive + + # Deterministic list of LFS object IDs, then compute a portable key: + # - `git lfs ls-files -l` lists all tracked LFS objects with their SHA-256 + # - `awk '{print $1}'` extracts just the SHA field + # - `sort` sorts in byte order (hex hashes sort the same everywhere) + # This ensures the file content is identical regardless of OS or locale + - name: Git Create LFS id list + shell: bash + run: git lfs ls-files -l | awk '{print $1}' | sort > .lfs-assets-id + + - name: Git Expose LFS cache key + id: expose-key + shell: bash + env: + LFS_KEY: lfs-${{ hashFiles('.lfs-assets-id') }}-v1 + run: echo "lfs_key=$LFS_KEY" >> "$GITHUB_OUTPUT" + + - name: Git Setup LFS Cache + uses: actions/cache@v5 + with: + path: .git/lfs + key: ${{ steps.expose-key.outputs.lfs_key }} + + - name: Git Pull LFS + shell: bash + run: git lfs pull + Build: + needs: WarmLFS strategy: matrix: options: - os: ubuntu-latest - framework: net7.0 + framework: net10.0 sdk-preview: true runtime: -x64 codecov: false - os: macos-latest - framework: net7.0 + framework: net10.0 sdk-preview: true runtime: -x64 codecov: false - os: windows-latest - framework: net7.0 + framework: net10.0 sdk-preview: true runtime: -x64 codecov: true - os: ubuntu-latest - framework: net6.0 + framework: net8.0 runtime: -x64 codecov: false - os: macos-latest - framework: net6.0 + framework: net8.0 runtime: -x64 codecov: false - os: windows-latest - framework: net6.0 + framework: net8.0 runtime: -x64 codecov: false @@ -58,25 +106,22 @@ jobs: fetch-depth: 0 submodules: recursive - # See https://github.com/actions/checkout/issues/165#issuecomment-657673315 - - name: Git Create LFS FileList - run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id - + # Use the warmed key from WarmLFS. Do not recompute or recreate .lfs-assets-id here. - name: Git Setup LFS Cache - uses: actions/cache@v4 - id: lfs-cache + uses: actions/cache@v5 with: path: .git/lfs - key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}-v1 + key: ${{ needs.WarmLFS.outputs.lfs_key }} - name: Git Pull LFS + shell: bash run: git lfs pull - name: NuGet Install uses: NuGet/setup-nuget@v2 - name: NuGet Setup Cache - uses: actions/cache@v4 + uses: actions/cache@v5 id: nuget-cache with: path: ~/.nuget @@ -112,11 +157,18 @@ jobs: s3rver -d . & - name: DotNet Setup - uses: actions/setup-dotnet@v4 + if: ${{ matrix.options.sdk-preview != true }} + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 8.0.x + + - name: DotNet Setup Preview + if: ${{ matrix.options.sdk-preview == true }} + uses: actions/setup-dotnet@v5 with: dotnet-version: | - 7.0.x - 6.0.x + 10.0.x - name: DotNet Build if: ${{ matrix.options.sdk-preview != true }} @@ -153,6 +205,7 @@ jobs: if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors') with: flags: unittests + token: ${{ secrets.CODECOV_TOKEN }} Publish: needs: [Build] @@ -178,7 +231,7 @@ jobs: uses: NuGet/setup-nuget@v2 - name: NuGet Setup Cache - uses: actions/cache@v4 + uses: actions/cache@v5 id: nuget-cache with: path: ~/.nuget diff --git a/samples/ImageSharp.Web.Sample/ImageSharp.Web.Sample.csproj b/samples/ImageSharp.Web.Sample/ImageSharp.Web.Sample.csproj index d20146da..f4b67405 100644 --- a/samples/ImageSharp.Web.Sample/ImageSharp.Web.Sample.csproj +++ b/samples/ImageSharp.Web.Sample/ImageSharp.Web.Sample.csproj @@ -1,10 +1,9 @@ - net6.0 + net8.0 enable enable - 10 diff --git a/samples/ImageSharp.Web.Sample/Pages/Index.cshtml b/samples/ImageSharp.Web.Sample/Pages/Index.cshtml index 73ad597b..74cb5f15 100644 --- a/samples/ImageSharp.Web.Sample/Pages/Index.cshtml +++ b/samples/ImageSharp.Web.Sample/Pages/Index.cshtml @@ -237,7 +237,7 @@ sixlabors.imagesharp.web.png?width=300&bgcolor=128,28,32

- +

@@ -253,7 +253,7 @@ sixlabors.imagesharp.web.png?width=300&bgcolor=128,28,32,128

- +

diff --git a/samples/ImageSharp.Web.Sample/Pages/_ViewImports.cshtml b/samples/ImageSharp.Web.Sample/Pages/_ViewImports.cshtml index 05714033..a811452d 100644 --- a/samples/ImageSharp.Web.Sample/Pages/_ViewImports.cshtml +++ b/samples/ImageSharp.Web.Sample/Pages/_ViewImports.cshtml @@ -1,4 +1,5 @@ @using SixLabors.ImageSharp +@using SixLabors.ImageSharp.PixelFormats @using SixLabors.ImageSharp.Processing @using SixLabors.ImageSharp.Web @using ImageSharp.Web.Sample diff --git a/samples/ImageSharp.Web.Sample/Program.cs b/samples/ImageSharp.Web.Sample/Program.cs index 44a5de87..d82ee33b 100644 --- a/samples/ImageSharp.Web.Sample/Program.cs +++ b/samples/ImageSharp.Web.Sample/Program.cs @@ -1,9 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.Web; using SixLabors.ImageSharp.Web.Caching; using SixLabors.ImageSharp.Web.Commands; -using SixLabors.ImageSharp.Web.DependencyInjection; using SixLabors.ImageSharp.Web.Processors; using SixLabors.ImageSharp.Web.Providers; @@ -27,7 +27,7 @@ public static void Main(string[] args) services.AddRazorPages(); // TODO: Enable HMAC - services.AddImageSharp(options => options.HMACSecretKey = new byte[] { 1, 2, 3, 4, 5 }) + services.AddImageSharp(options => options.HMACSecretKey = [1, 2, 3, 4, 5]) .SetRequestParser() .Configure(options => { diff --git a/shared-infrastructure b/shared-infrastructure index f0d7ed20..bed6f53b 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit f0d7ed20b36ab1f9e379ca3bee528e6efd991b00 +Subproject commit bed6f53bea0239e4afa19e81c24a6fff421707e1 diff --git a/src/ImageSharp.Web.Providers.AWS/AmazonS3BucketClient.cs b/src/ImageSharp.Web.Providers.AWS/AmazonS3BucketClient.cs index d8940666..d67fad61 100644 --- a/src/ImageSharp.Web.Providers.AWS/AmazonS3BucketClient.cs +++ b/src/ImageSharp.Web.Providers.AWS/AmazonS3BucketClient.cs @@ -3,7 +3,7 @@ using Amazon.S3; -namespace SixLabors.ImageSharp.Web; +namespace SixLabors.ImageSharp.Web.AWS; /// /// Represents a scoped Amazon S3 client instance that is explicitly associated with a single S3 bucket. diff --git a/src/ImageSharp.Web.Providers.AWS/AmazonS3ClientFactory.cs b/src/ImageSharp.Web.Providers.AWS/AmazonS3ClientFactory.cs index ff21b56a..347d4254 100644 --- a/src/ImageSharp.Web.Providers.AWS/AmazonS3ClientFactory.cs +++ b/src/ImageSharp.Web.Providers.AWS/AmazonS3ClientFactory.cs @@ -5,7 +5,7 @@ using Amazon.Runtime; using Amazon.S3; -namespace SixLabors.ImageSharp.Web; +namespace SixLabors.ImageSharp.Web.AWS; internal static class AmazonS3ClientFactory { diff --git a/src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCache.cs b/src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCache.cs index aef41ac7..a3b9f5b3 100644 --- a/src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCache.cs +++ b/src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCache.cs @@ -5,10 +5,11 @@ using Amazon.S3; using Amazon.S3.Model; using Microsoft.Extensions.Options; +using SixLabors.ImageSharp.Web.AWS.Resolvers; +using SixLabors.ImageSharp.Web.Caching; using SixLabors.ImageSharp.Web.Resolvers; -using SixLabors.ImageSharp.Web.Resolvers.AWS; -namespace SixLabors.ImageSharp.Web.Caching.AWS; +namespace SixLabors.ImageSharp.Web.AWS.Caching; /// /// Implements an AWS S3 Storage based cache. diff --git a/src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCacheOptions.cs b/src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCacheOptions.cs index e9c4a606..60b74439 100644 --- a/src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCacheOptions.cs +++ b/src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCacheOptions.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Web.Caching.AWS; +namespace SixLabors.ImageSharp.Web.AWS.Caching; /// /// Configuration options for the provider. diff --git a/src/ImageSharp.Web.Providers.AWS/IAWSS3BucketClientOptions.cs b/src/ImageSharp.Web.Providers.AWS/IAWSS3BucketClientOptions.cs index 62bd79fe..452c9ce9 100644 --- a/src/ImageSharp.Web.Providers.AWS/IAWSS3BucketClientOptions.cs +++ b/src/ImageSharp.Web.Providers.AWS/IAWSS3BucketClientOptions.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Web; +namespace SixLabors.ImageSharp.Web.AWS; /// /// Provides a common interface for AWS S3 Bucket Client Options. diff --git a/src/ImageSharp.Web.Providers.AWS/ImageSharp.Web.Providers.AWS.csproj b/src/ImageSharp.Web.Providers.AWS/ImageSharp.Web.Providers.AWS.csproj index 41a35fa7..a8311d23 100644 --- a/src/ImageSharp.Web.Providers.AWS/ImageSharp.Web.Providers.AWS.csproj +++ b/src/ImageSharp.Web.Providers.AWS/ImageSharp.Web.Providers.AWS.csproj @@ -3,7 +3,7 @@ SixLabors.ImageSharp.Web.Providers.AWS SixLabors.ImageSharp.Web.Providers.AWS - SixLabors.ImageSharp.Web + SixLabors.ImageSharp.Web.AWS SixLabors.ImageSharp.Web.Providers.AWS sixlabors.imagesharp.web.128.png LICENSE @@ -20,19 +20,19 @@ - - 3.0 + + 4.0 - net7.0;net6.0 + net8.0;net10.0 - net6.0 + net8.0 @@ -43,7 +43,7 @@ - + diff --git a/src/ImageSharp.Web.Providers.AWS/Providers/AWSS3StorageImageProvider.cs b/src/ImageSharp.Web.Providers.AWS/Providers/AWSS3StorageImageProvider.cs index 20ab9b15..f8f10389 100644 --- a/src/ImageSharp.Web.Providers.AWS/Providers/AWSS3StorageImageProvider.cs +++ b/src/ImageSharp.Web.Providers.AWS/Providers/AWSS3StorageImageProvider.cs @@ -6,10 +6,11 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Options; +using SixLabors.ImageSharp.Web.AWS.Resolvers; +using SixLabors.ImageSharp.Web.Providers; using SixLabors.ImageSharp.Web.Resolvers; -using SixLabors.ImageSharp.Web.Resolvers.AWS; -namespace SixLabors.ImageSharp.Web.Providers.AWS; +namespace SixLabors.ImageSharp.Web.AWS.Providers; /// /// Returns images stored in AWS S3. @@ -19,13 +20,13 @@ public class AWSS3StorageImageProvider : IImageProvider, IDisposable /// /// Character array to remove from paths. /// - private static readonly char[] SlashChars = { '\\', '/' }; + private static readonly char[] SlashChars = ['\\', '/']; /// /// The containers for the blob services. /// private readonly Dictionary buckets - = new(); + = []; private readonly AWSS3StorageImageProviderOptions storageOptions; private Func? match; @@ -154,7 +155,7 @@ private bool IsMatch(HttpContext context) } // ref https://github.com/aws/aws-sdk-net/blob/master/sdk/src/Services/S3/Custom/_bcl/IO/S3FileInfo.cs#L118 - private static async Task KeyExists(IAmazonS3 s3Client, string bucketName, string key) + private static async Task KeyExists(AmazonS3Client s3Client, string bucketName, string key) { try { diff --git a/src/ImageSharp.Web.Providers.AWS/Providers/AWSS3StorageImageProviderOptions.cs b/src/ImageSharp.Web.Providers.AWS/Providers/AWSS3StorageImageProviderOptions.cs index 187aec7e..93aa1cc2 100644 --- a/src/ImageSharp.Web.Providers.AWS/Providers/AWSS3StorageImageProviderOptions.cs +++ b/src/ImageSharp.Web.Providers.AWS/Providers/AWSS3StorageImageProviderOptions.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Web.Providers.AWS; +namespace SixLabors.ImageSharp.Web.AWS.Providers; /// /// Configuration options for the provider. diff --git a/src/ImageSharp.Web.Providers.AWS/Resolvers/AWSS3StorageCacheResolver.cs b/src/ImageSharp.Web.Providers.AWS/Resolvers/AWSS3StorageCacheResolver.cs index 2add992f..78b534b8 100644 --- a/src/ImageSharp.Web.Providers.AWS/Resolvers/AWSS3StorageCacheResolver.cs +++ b/src/ImageSharp.Web.Providers.AWS/Resolvers/AWSS3StorageCacheResolver.cs @@ -3,8 +3,9 @@ using Amazon.S3; using Amazon.S3.Model; +using SixLabors.ImageSharp.Web.Resolvers; -namespace SixLabors.ImageSharp.Web.Resolvers.AWS; +namespace SixLabors.ImageSharp.Web.AWS.Resolvers; /// /// Provides means to manage image buffers within the . @@ -34,7 +35,7 @@ public AWSS3StorageCacheResolver(IAmazonS3 amazonS3, string bucketName, string i /// public Task GetMetaDataAsync() { - Dictionary dict = new(); + Dictionary dict = []; foreach (string key in this.metadata.Keys) { // Trim automatically added x-amz-meta- diff --git a/src/ImageSharp.Web.Providers.AWS/Resolvers/AWSS3StorageImageResolver.cs b/src/ImageSharp.Web.Providers.AWS/Resolvers/AWSS3StorageImageResolver.cs index 42e042fd..65c5b8a1 100644 --- a/src/ImageSharp.Web.Providers.AWS/Resolvers/AWSS3StorageImageResolver.cs +++ b/src/ImageSharp.Web.Providers.AWS/Resolvers/AWSS3StorageImageResolver.cs @@ -4,8 +4,9 @@ using System.Net.Http.Headers; using Amazon.S3; using Amazon.S3.Model; +using SixLabors.ImageSharp.Web.Resolvers; -namespace SixLabors.ImageSharp.Web.Resolvers.AWS; +namespace SixLabors.ImageSharp.Web.AWS.Resolvers; /// /// Provides means to manage image buffers within the AWS S3 file system. diff --git a/src/ImageSharp.Web.Providers.Azure/Caching/AzureBlobStorageCache.cs b/src/ImageSharp.Web.Providers.Azure/Caching/AzureBlobStorageCache.cs index e49d281a..6252ac33 100644 --- a/src/ImageSharp.Web.Providers.Azure/Caching/AzureBlobStorageCache.cs +++ b/src/ImageSharp.Web.Providers.Azure/Caching/AzureBlobStorageCache.cs @@ -5,10 +5,11 @@ using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; using Microsoft.Extensions.Options; +using SixLabors.ImageSharp.Web.Azure.Resolvers; +using SixLabors.ImageSharp.Web.Caching; using SixLabors.ImageSharp.Web.Resolvers; -using SixLabors.ImageSharp.Web.Resolvers.Azure; -namespace SixLabors.ImageSharp.Web.Caching.Azure; +namespace SixLabors.ImageSharp.Web.Azure.Caching; /// /// Implements an Azure Blob Storage based cache. diff --git a/src/ImageSharp.Web.Providers.Azure/Caching/AzureBlobStorageCacheOptions.cs b/src/ImageSharp.Web.Providers.Azure/Caching/AzureBlobStorageCacheOptions.cs index ab119aa6..d41229ca 100644 --- a/src/ImageSharp.Web.Providers.Azure/Caching/AzureBlobStorageCacheOptions.cs +++ b/src/ImageSharp.Web.Providers.Azure/Caching/AzureBlobStorageCacheOptions.cs @@ -3,7 +3,7 @@ using Azure.Storage.Blobs; -namespace SixLabors.ImageSharp.Web.Caching.Azure; +namespace SixLabors.ImageSharp.Web.Azure.Caching; /// /// Configuration options for the . diff --git a/src/ImageSharp.Web.Providers.Azure/ImageSharp.Web.Providers.Azure.csproj b/src/ImageSharp.Web.Providers.Azure/ImageSharp.Web.Providers.Azure.csproj index da7e9305..c54d7a7f 100644 --- a/src/ImageSharp.Web.Providers.Azure/ImageSharp.Web.Providers.Azure.csproj +++ b/src/ImageSharp.Web.Providers.Azure/ImageSharp.Web.Providers.Azure.csproj @@ -1,9 +1,9 @@ - + SixLabors.ImageSharp.Web.Providers.Azure SixLabors.ImageSharp.Web.Providers.Azure - SixLabors.ImageSharp.Web + SixLabors.ImageSharp.Web.Azure SixLabors.ImageSharp.Web.Providers.Azure sixlabors.imagesharp.web.128.png LICENSE @@ -20,19 +20,19 @@ - - 3.0 + + 4.0 - net7.0;net6.0 + net8.0;net10.0 - net6.0 + net8.0 @@ -43,7 +43,7 @@ - + diff --git a/src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProvider.cs b/src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProvider.cs index 60069a55..ca95de7e 100644 --- a/src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProvider.cs +++ b/src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProvider.cs @@ -5,10 +5,11 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Options; +using SixLabors.ImageSharp.Web.Azure.Resolvers; +using SixLabors.ImageSharp.Web.Providers; using SixLabors.ImageSharp.Web.Resolvers; -using SixLabors.ImageSharp.Web.Resolvers.Azure; -namespace SixLabors.ImageSharp.Web.Providers.Azure; +namespace SixLabors.ImageSharp.Web.Azure.Providers; /// /// Returns images stored in Azure Blob Storage. @@ -18,13 +19,13 @@ public class AzureBlobStorageImageProvider : IImageProvider /// /// Character array to remove from paths. /// - private static readonly char[] SlashChars = { '\\', '/' }; + private static readonly char[] SlashChars = ['\\', '/']; /// /// The containers for the blob services. /// private readonly Dictionary containers - = new(); + = []; /// /// Contains various helper methods based on the current configuration. diff --git a/src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProviderOptions.cs b/src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProviderOptions.cs index 9b1b8a1b..fa30977d 100644 --- a/src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProviderOptions.cs +++ b/src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProviderOptions.cs @@ -3,7 +3,7 @@ using Azure.Storage.Blobs; -namespace SixLabors.ImageSharp.Web.Providers.Azure; +namespace SixLabors.ImageSharp.Web.Azure.Providers; /// /// Configuration options for the provider. diff --git a/src/ImageSharp.Web.Providers.Azure/Resolvers/AzureBlobStorageCacheResolver.cs b/src/ImageSharp.Web.Providers.Azure/Resolvers/AzureBlobStorageCacheResolver.cs index cdfad480..5f6062ec 100644 --- a/src/ImageSharp.Web.Providers.Azure/Resolvers/AzureBlobStorageCacheResolver.cs +++ b/src/ImageSharp.Web.Providers.Azure/Resolvers/AzureBlobStorageCacheResolver.cs @@ -3,9 +3,10 @@ using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; -using SixLabors.ImageSharp.Web.Caching.Azure; +using SixLabors.ImageSharp.Web.Azure.Caching; +using SixLabors.ImageSharp.Web.Resolvers; -namespace SixLabors.ImageSharp.Web.Resolvers.Azure; +namespace SixLabors.ImageSharp.Web.Azure.Resolvers; /// /// Provides means to manage image buffers within the . diff --git a/src/ImageSharp.Web.Providers.Azure/Resolvers/AzureBlobStorageImageResolver.cs b/src/ImageSharp.Web.Providers.Azure/Resolvers/AzureBlobStorageImageResolver.cs index 3b22d794..4fa2ec66 100644 --- a/src/ImageSharp.Web.Providers.Azure/Resolvers/AzureBlobStorageImageResolver.cs +++ b/src/ImageSharp.Web.Providers.Azure/Resolvers/AzureBlobStorageImageResolver.cs @@ -4,8 +4,9 @@ using System.Net.Http.Headers; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; +using SixLabors.ImageSharp.Web.Resolvers; -namespace SixLabors.ImageSharp.Web.Resolvers.Azure; +namespace SixLabors.ImageSharp.Web.Azure.Resolvers; /// /// Provides means to manage image buffers within the Azure Blob file system. diff --git a/src/ImageSharp.Web/DependencyInjection/ApplicationBuilderExtensions.cs b/src/ImageSharp.Web/ApplicationBuilderExtensions.cs similarity index 93% rename from src/ImageSharp.Web/DependencyInjection/ApplicationBuilderExtensions.cs rename to src/ImageSharp.Web/ApplicationBuilderExtensions.cs index e2f896dc..0246de2b 100644 --- a/src/ImageSharp.Web/DependencyInjection/ApplicationBuilderExtensions.cs +++ b/src/ImageSharp.Web/ApplicationBuilderExtensions.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Builder; using SixLabors.ImageSharp.Web.Middleware; -namespace SixLabors.ImageSharp.Web.DependencyInjection; +namespace SixLabors.ImageSharp.Web; /// /// Extension methods for to simplify middleware registration. diff --git a/src/ImageSharp.Web/Caching/HexEncoder.cs b/src/ImageSharp.Web/Caching/HexEncoder.cs index acf72787..6541a802 100644 --- a/src/ImageSharp.Web/Caching/HexEncoder.cs +++ b/src/ImageSharp.Web/Caching/HexEncoder.cs @@ -12,13 +12,13 @@ namespace SixLabors.ImageSharp.Web.Caching; internal static class HexEncoder { // LUT's that provide the hexidecimal representation of each possible byte value. - private static readonly char[] HexLutBase = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + private static readonly char[] HexLutBase = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; // The base LUT arranged in 16x each item order. 0 * 16, 1 * 16, .... F * 16 - private static readonly char[] HexLutHi = Enumerable.Range(0, 256).Select(x => HexLutBase[x / 0x10]).ToArray(); + private static readonly char[] HexLutHi = [.. Enumerable.Range(0, 256).Select(x => HexLutBase[x / 0x10])]; // The base LUT repeated 16x. - private static readonly char[] HexLutLo = Enumerable.Range(0, 256).Select(x => HexLutBase[x % 0x10]).ToArray(); + private static readonly char[] HexLutLo = [.. Enumerable.Range(0, 256).Select(x => HexLutBase[x % 0x10])]; /// /// Converts a to a hexidecimal formatted padded to 2 digits. @@ -32,7 +32,7 @@ public static unsafe string Encode(ReadOnlySpan bytes) { return string.Create(bytes.Length * 2, (Ptr: (IntPtr)bytesPtr, bytes.Length), (chars, args) => { - var ros = new ReadOnlySpan((byte*)args.Ptr, args.Length); + ReadOnlySpan ros = new((byte*)args.Ptr, args.Length); EncodeToUtf16(ros, chars); }); } diff --git a/src/ImageSharp.Web/Caching/ICacheHash.cs b/src/ImageSharp.Web/Caching/ICacheHash.cs index 26324709..c70b70b8 100644 --- a/src/ImageSharp.Web/Caching/ICacheHash.cs +++ b/src/ImageSharp.Web/Caching/ICacheHash.cs @@ -14,5 +14,5 @@ public interface ICacheHash /// The input value to hash. /// The length of the returned hash without any extensions. /// The . - string Create(string value, uint length); + public string Create(string value, uint length); } diff --git a/src/ImageSharp.Web/Caching/ICacheKey.cs b/src/ImageSharp.Web/Caching/ICacheKey.cs index d7d3ae43..80282631 100644 --- a/src/ImageSharp.Web/Caching/ICacheKey.cs +++ b/src/ImageSharp.Web/Caching/ICacheKey.cs @@ -19,5 +19,5 @@ public interface ICacheKey /// /// The cache key. /// - string Create(HttpContext context, CommandCollection commands); + public string Create(HttpContext context, CommandCollection commands); } diff --git a/src/ImageSharp.Web/Caching/IImageCache.cs b/src/ImageSharp.Web/Caching/IImageCache.cs index 1ac8e5cd..cdd790f0 100644 --- a/src/ImageSharp.Web/Caching/IImageCache.cs +++ b/src/ImageSharp.Web/Caching/IImageCache.cs @@ -16,7 +16,7 @@ public interface IImageCache /// /// The cache key. /// The . - Task GetAsync(string key); + public Task GetAsync(string key); /// /// Sets the value associated with the specified key. @@ -25,5 +25,5 @@ public interface IImageCache /// The stream containing the image to store. /// The associated with the image to store. /// The task. - Task SetAsync(string key, Stream stream, ImageCacheMetadata metadata); + public Task SetAsync(string key, Stream stream, ImageCacheMetadata metadata); } diff --git a/src/ImageSharp.Web/Caching/LegacyV1CacheKey.cs b/src/ImageSharp.Web/Caching/LegacyV1CacheKey.cs index 64b56e0b..03bba64d 100644 --- a/src/ImageSharp.Web/Caching/LegacyV1CacheKey.cs +++ b/src/ImageSharp.Web/Caching/LegacyV1CacheKey.cs @@ -22,16 +22,16 @@ public string Create(HttpContext context, CommandCollection commands) string pathBase = context.Request.PathBase.ToString(); if (!string.IsNullOrWhiteSpace(pathBase)) { - sb.AppendFormat(CultureInfo.InvariantCulture, "{0}/", pathBase); + _ = sb.AppendFormat(CultureInfo.InvariantCulture, "{0}/", pathBase); } string path = context.Request.Path.ToString(); if (!string.IsNullOrWhiteSpace(path)) { - sb.Append(path); + _ = sb.Append(path); } - sb.Append(QueryString.Create(commands)); + _ = sb.Append(QueryString.Create(commands)); return sb.ToString().ToLowerInvariant(); } diff --git a/src/ImageSharp.Web/Caching/LruCache/ConcurrentTLruCache{TKey,TValue}.cs b/src/ImageSharp.Web/Caching/LruCache/ConcurrentTLruCache{TKey,TValue}.cs index dbb1cf16..6d44700e 100644 --- a/src/ImageSharp.Web/Caching/LruCache/ConcurrentTLruCache{TKey,TValue}.cs +++ b/src/ImageSharp.Web/Caching/LruCache/ConcurrentTLruCache{TKey,TValue}.cs @@ -148,7 +148,7 @@ public TValue GetOrAdd(TKey key, Func valueFactory) if (this.dictionary.TryAdd(key, newItem)) { this.hotQueue.Enqueue(newItem); - Interlocked.Increment(ref this.hotCount); + _ = Interlocked.Increment(ref this.hotCount); this.Cycle(); return newItem.Value; } @@ -177,7 +177,7 @@ public async Task GetOrAddAsync(TKey key, Func> value if (this.dictionary.TryAdd(key, newItem)) { this.hotQueue.Enqueue(newItem); - Interlocked.Increment(ref this.hotCount); + _ = Interlocked.Increment(ref this.hotCount); this.Cycle(); return newItem.Value; } @@ -260,7 +260,7 @@ private void CycleHot() { if (this.hotCount > this.hotCapacity) { - Interlocked.Decrement(ref this.hotCount); + _ = Interlocked.Decrement(ref this.hotCount); if (this.hotQueue.TryDequeue(out LongTickCountLruItem? item)) { @@ -269,7 +269,7 @@ private void CycleHot() } else { - Interlocked.Increment(ref this.hotCount); + _ = Interlocked.Increment(ref this.hotCount); } } } @@ -278,7 +278,7 @@ private void CycleWarm() { if (this.warmCount > this.warmCapacity) { - Interlocked.Decrement(ref this.warmCount); + _ = Interlocked.Decrement(ref this.warmCount); if (this.warmQueue.TryDequeue(out LongTickCountLruItem? item)) { @@ -298,7 +298,7 @@ private void CycleWarm() } else { - Interlocked.Increment(ref this.warmCount); + _ = Interlocked.Increment(ref this.warmCount); } } } @@ -307,7 +307,7 @@ private void CycleCold() { if (this.coldCount > this.coldCapacity) { - Interlocked.Decrement(ref this.coldCount); + _ = Interlocked.Decrement(ref this.coldCount); if (this.coldQueue.TryDequeue(out LongTickCountLruItem? item)) { @@ -324,7 +324,7 @@ private void CycleCold() } else { - Interlocked.Increment(ref this.coldCount); + _ = Interlocked.Increment(ref this.coldCount); } } } @@ -338,11 +338,11 @@ private void Move(LongTickCountLruItem item, ItemDestination where { case ItemDestination.Warm: this.warmQueue.Enqueue(item); - Interlocked.Increment(ref this.warmCount); + _ = Interlocked.Increment(ref this.warmCount); break; case ItemDestination.Cold: this.coldQueue.Enqueue(item); - Interlocked.Increment(ref this.coldCount); + _ = Interlocked.Increment(ref this.coldCount); break; case ItemDestination.Remove: if (!item.WasRemoved) diff --git a/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs b/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs index 34fe94a3..f70f8c8b 100644 --- a/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs +++ b/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs @@ -100,7 +100,7 @@ public async Task SetAsync(string key, Stream stream, ImageCacheMetadata metadat // Ensure cache directory is created before creating files if (!Directory.Exists(directory) && directory is not null) { - Directory.CreateDirectory(directory); + _ = Directory.CreateDirectory(directory); } using (FileStream fileStream = File.Create(imagePath)) diff --git a/src/ImageSharp.Web/Caching/SHA256CacheHash.cs b/src/ImageSharp.Web/Caching/SHA256CacheHash.cs index 7eeae17a..7d3181b6 100644 --- a/src/ImageSharp.Web/Caching/SHA256CacheHash.cs +++ b/src/ImageSharp.Web/Caching/SHA256CacheHash.cs @@ -55,11 +55,11 @@ public string Create(string value, uint length) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static string HashValue(ReadOnlySpan value, uint length, Span bufferSpan) { - Encoding.ASCII.GetBytes(value, bufferSpan); + _ = Encoding.ASCII.GetBytes(value, bufferSpan); // Hashed output maxes out at 32 bytes @ 256bit/8 so we're safe to use stackalloc Span hash = stackalloc byte[32]; - SHA256.TryHashData(bufferSpan, hash, out int _); + _ = SHA256.TryHashData(bufferSpan, hash, out _); // Length maxes out at 64 since we throw if options is greater return HexEncoder.Encode(hash[..(int)(length / 2)]); diff --git a/src/ImageSharp.Web/Commands/CommandCollectionExtensions.cs b/src/ImageSharp.Web/Commands/CommandCollectionExtensions.cs index 126c990a..b9f4a220 100644 --- a/src/ImageSharp.Web/Commands/CommandCollectionExtensions.cs +++ b/src/ImageSharp.Web/Commands/CommandCollectionExtensions.cs @@ -16,7 +16,7 @@ public static class CommandCollectionExtensions /// The value associated with the specified key or the default value. public static string? GetValueOrDefault(this CommandCollection collection, string key) { - collection.TryGetValue(key, out KeyValuePair result); + _ = collection.TryGetValue(key, out KeyValuePair result); return result.Value; } } diff --git a/src/ImageSharp.Web/Commands/CommandParser.cs b/src/ImageSharp.Web/Commands/CommandParser.cs index 4bd0f534..1df81e9d 100644 --- a/src/ImageSharp.Web/Commands/CommandParser.cs +++ b/src/ImageSharp.Web/Commands/CommandParser.cs @@ -23,7 +23,7 @@ public sealed class CommandParser public CommandParser(IEnumerable converters) { Guard.NotNull(converters, nameof(converters)); - this.converters = converters.ToArray(); + this.converters = [.. converters]; } /// diff --git a/src/ImageSharp.Web/Commands/Converters/ArrayConverter{T}.cs b/src/ImageSharp.Web/Commands/Converters/ArrayConverter{T}.cs index 426da7e3..451ce3ab 100644 --- a/src/ImageSharp.Web/Commands/Converters/ArrayConverter{T}.cs +++ b/src/ImageSharp.Web/Commands/Converters/ArrayConverter{T}.cs @@ -28,7 +28,7 @@ public T[] ConvertFrom( return Array.Empty(); } - List result = new(); + List result = []; foreach (string pill in GetStringArray(value, culture)) { T? item = parser.ParseValue(pill, culture); @@ -38,7 +38,7 @@ public T[] ConvertFrom( } } - return result.ToArray(); + return [.. result]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -48,6 +48,6 @@ private static string[] GetStringArray(string input, CultureInfo culture) // TODO: Can we use StringSplit Enumerator here? // https://github.com/dotnet/runtime/issues/934 - return input.Split(separator).Select(s => s.Trim()).ToArray(); + return [.. input.Split(separator).Select(s => s.Trim())]; } } diff --git a/src/ImageSharp.Web/Commands/Converters/ColorConverter.cs b/src/ImageSharp.Web/Commands/Converters/ColorConverter.cs index ccf2c111..3bdc1150 100644 --- a/src/ImageSharp.Web/Commands/Converters/ColorConverter.cs +++ b/src/ImageSharp.Web/Commands/Converters/ColorConverter.cs @@ -5,24 +5,25 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Web.Commands.Converters; /// /// Allows the conversion of strings into rgba32 pixel colors. /// -public sealed class ColorConverter : ICommandConverter +public sealed partial class ColorConverter : ICommandConverter { /// /// The web color hexadecimal regex. Matches strings arranged /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. /// - private static readonly Regex HexColorRegex = new("([0-9a-fA-F][^,;.-]\\B{3}){1,2}", RegexOptions.Compiled); + private static readonly Regex HexColorRegex = HexRegex(); /// /// The number color regex. /// - private static readonly Regex NumberRegex = new(@"\d+", RegexOptions.Compiled); + private static readonly Regex NumberRegex = NumberColorRegex(); /// /// The color constants table map. @@ -69,8 +70,8 @@ public Color ConvertFrom(CommandParser parser, CultureInfo culture, string? valu return rgba?.Count switch { - 4 => Color.FromRgba(rgba[0], rgba[1], rgba[2], rgba[3]), - 3 => Color.FromRgb(rgba[0], rgba[1], rgba[2]), + 4 => Color.FromPixel(new(rgba[0], rgba[1], rgba[2], rgba[3])), + 3 => Color.FromPixel(new(rgba[0], rgba[1], rgba[2])), _ => default, }; } @@ -85,9 +86,9 @@ public Color ConvertFrom(CommandParser parser, CultureInfo culture, string? valu return default; } - private static IDictionary InitializeColorConstantsTable() + private static Dictionary InitializeColorConstantsTable() { - IDictionary table = new Dictionary(StringComparer.OrdinalIgnoreCase); + Dictionary table = new(StringComparer.OrdinalIgnoreCase); foreach (FieldInfo field in typeof(Color).GetFields(BindingFlags.Public | BindingFlags.Static)) { @@ -99,4 +100,10 @@ private static IDictionary InitializeColorConstantsTable() return table; } + + [GeneratedRegex(@"\d+", RegexOptions.Compiled)] + private static partial Regex NumberColorRegex(); + + [GeneratedRegex("([0-9a-fA-F][^,;.-]\\B{3}){1,2}", RegexOptions.Compiled)] + private static partial Regex HexRegex(); } diff --git a/src/ImageSharp.Web/Commands/Converters/ConverterUtility.cs b/src/ImageSharp.Web/Commands/Converters/ConverterUtility.cs index c924e35c..18104b0f 100644 --- a/src/ImageSharp.Web/Commands/Converters/ConverterUtility.cs +++ b/src/ImageSharp.Web/Commands/Converters/ConverterUtility.cs @@ -6,6 +6,7 @@ using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Web.Commands.Converters; + internal static class ConverterUtility { /// diff --git a/src/ImageSharp.Web/Commands/Converters/EnumConverter.cs b/src/ImageSharp.Web/Commands/Converters/EnumConverter.cs index 43573145..3d226c93 100644 --- a/src/ImageSharp.Web/Commands/Converters/EnumConverter.cs +++ b/src/ImageSharp.Web/Commands/Converters/EnumConverter.cs @@ -29,7 +29,7 @@ public sealed class EnumConverter : ICommandConverter { if (string.IsNullOrWhiteSpace(value)) { - return Activator.CreateInstance(propertyType); + return Enum.ToObject(propertyType, 0); } try @@ -51,7 +51,7 @@ public sealed class EnumConverter : ICommandConverter catch { // Just return the default value - return Activator.CreateInstance(propertyType); + return Enum.ToObject(propertyType, 0); } } @@ -66,5 +66,5 @@ private static string[] GetStringArray(string input, char separator) // TODO: Can we use StringSplit Enumerator here? // https://github.com/dotnet/runtime/issues/934 - => input.Split(separator).Select(s => s.Trim()).ToArray(); + => [.. input.Split(separator).Select(s => s.Trim())]; } diff --git a/src/ImageSharp.Web/Commands/Converters/ICommandConverter.cs b/src/ImageSharp.Web/Commands/Converters/ICommandConverter.cs index f81c75e5..aa6eaa1e 100644 --- a/src/ImageSharp.Web/Commands/Converters/ICommandConverter.cs +++ b/src/ImageSharp.Web/Commands/Converters/ICommandConverter.cs @@ -14,7 +14,7 @@ public interface ICommandConverter /// /// Gets the type this converter returns. /// - Type Type { get; } + public Type Type { get; } } /// @@ -34,5 +34,5 @@ public interface ICommandConverter : ICommandConverter /// The to convert. /// The property type that the converter will convert to. /// The conversion cannot be performed. - T? ConvertFrom(CommandParser parser, CultureInfo culture, string? value, Type propertyType); + public T? ConvertFrom(CommandParser parser, CultureInfo culture, string? value, Type propertyType); } diff --git a/src/ImageSharp.Web/Commands/Converters/ListConverter{T}.cs b/src/ImageSharp.Web/Commands/Converters/ListConverter{T}.cs index 5a1e35ca..8a1535db 100644 --- a/src/ImageSharp.Web/Commands/Converters/ListConverter{T}.cs +++ b/src/ImageSharp.Web/Commands/Converters/ListConverter{T}.cs @@ -23,7 +23,7 @@ public List ConvertFrom( string? value, Type propertyType) { - List result = new(); + List result = []; if (string.IsNullOrWhiteSpace(value)) { return result; @@ -48,6 +48,6 @@ private static string[] GetStringArray(string input, CultureInfo culture) // TODO: Can we use StringSplit Enumerator here? // https://github.com/dotnet/runtime/issues/934 - return input.Split(separator).Select(s => s.Trim()).ToArray(); + return [.. input.Split(separator).Select(s => s.Trim())]; } } diff --git a/src/ImageSharp.Web/Commands/IRequestParser.cs b/src/ImageSharp.Web/Commands/IRequestParser.cs index 73aede92..48bc6cf7 100644 --- a/src/ImageSharp.Web/Commands/IRequestParser.cs +++ b/src/ImageSharp.Web/Commands/IRequestParser.cs @@ -15,5 +15,5 @@ public interface IRequestParser /// /// Encapsulates all HTTP-specific information about an individual HTTP request. /// The . - CommandCollection ParseRequestCommands(HttpContext context); + public CommandCollection ParseRequestCommands(HttpContext context); } diff --git a/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParser.cs b/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParser.cs index 89042ac2..f879463b 100644 --- a/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParser.cs +++ b/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParser.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Web.Commands; /// public class PresetOnlyQueryCollectionRequestParser : IRequestParser { - private readonly IDictionary presets; + private readonly Dictionary presets; /// /// The command constant for the preset query parameter. @@ -36,7 +36,7 @@ public CommandCollection ParseRequestCommands(HttpContext context) || !queryCollection.ContainsKey(QueryKey)) { // We return new here and below to ensure the collection is still mutable via events. - return new(); + return []; } StringValues query = queryCollection[QueryKey]; @@ -46,10 +46,10 @@ public CommandCollection ParseRequestCommands(HttpContext context) return collection; } - return new(); + return []; } - private static IDictionary ParsePresets( + private static Dictionary ParsePresets( IDictionary unparsedPresets) => unparsedPresets .Select(keyValue => @@ -58,7 +58,7 @@ private static IDictionary ParsePresets( private static CommandCollection ParsePreset(string unparsedPresetValue) { - CommandCollection transformed = new(); + CommandCollection transformed = []; foreach (QueryStringEnumerable.EncodedNameValuePair pair in new QueryStringEnumerable(unparsedPresetValue)) { // Last value wins. diff --git a/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParserOptions.cs b/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParserOptions.cs index 7c40e8a4..d138cc72 100644 --- a/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParserOptions.cs +++ b/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParserOptions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Web.Commands; @@ -11,5 +11,5 @@ public class PresetOnlyQueryCollectionRequestParserOptions /// /// Gets or sets the presets, which is a Dictionary of preset names to command query strings. /// - public IDictionary Presets { get; set; } = new Dictionary(); + public Dictionary Presets { get; set; } = []; } diff --git a/src/ImageSharp.Web/Commands/QueryCollectionRequestParser.cs b/src/ImageSharp.Web/Commands/QueryCollectionRequestParser.cs index 420fc019..7c813acd 100644 --- a/src/ImageSharp.Web/Commands/QueryCollectionRequestParser.cs +++ b/src/ImageSharp.Web/Commands/QueryCollectionRequestParser.cs @@ -18,10 +18,10 @@ public CommandCollection ParseRequestCommands(HttpContext context) if (query is null || query.Count == 0) { // We return new to ensure the collection is still mutable via events. - return new(); + return []; } - CommandCollection transformed = new(); + CommandCollection transformed = []; foreach (KeyValuePair pair in query) { // Use the indexer for both set and query. This replaces any previously parsed values. diff --git a/src/ImageSharp.Web/Commands/TypeConstants.cs b/src/ImageSharp.Web/Commands/TypeConstants.cs index c6460de5..249ff8f1 100644 --- a/src/ImageSharp.Web/Commands/TypeConstants.cs +++ b/src/ImageSharp.Web/Commands/TypeConstants.cs @@ -52,7 +52,7 @@ internal static class TypeConstants /// The collection of integral number types. /// public static readonly Type[] IntegralTypes = - { + [ Sbyte, Byte, Short, @@ -61,5 +61,5 @@ internal static class TypeConstants UInt, Long, ULong - }; + ]; } diff --git a/src/ImageSharp.Web/DependencyInjection/ServiceCollectionExtensions.cs b/src/ImageSharp.Web/DependencyInjection/ServiceCollectionExtensions.cs deleted file mode 100644 index 4a3a3e59..00000000 --- a/src/ImageSharp.Web/DependencyInjection/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Web.Caching; -using SixLabors.ImageSharp.Web.Commands; -using SixLabors.ImageSharp.Web.Commands.Converters; -using SixLabors.ImageSharp.Web.Middleware; -using SixLabors.ImageSharp.Web.Processors; -using SixLabors.ImageSharp.Web.Providers; -using SixLabors.ImageSharp.Web.Synchronization; - -namespace SixLabors.ImageSharp.Web.DependencyInjection; - -/// -/// Extension methods for to simplify middleware service registration. -/// -public static class ServiceCollectionExtensions -{ - /// - /// Adds ImageSharp services to the specified with the default options. - /// - /// The to add services to. - /// An that can be used to further configure the ImageSharp services. - public static IImageSharpBuilder AddImageSharp(this IServiceCollection services) - => AddImageSharp(services, _ => { }); - - /// - /// Adds ImageSharp services to the specified with the given options. - /// - /// The to add services to. - /// An to configure the provided . - /// An that can be used to further configure the ImageSharp services. - public static IImageSharpBuilder AddImageSharp( - this IServiceCollection services, - Action setupAction) - { - Guard.NotNull(services, nameof(services)); - Guard.NotNull(setupAction, nameof(setupAction)); - - IImageSharpBuilder builder = new ImageSharpBuilder(services); - - AddDefaultServices(builder, setupAction); - - return builder; - } - - private static void AddDefaultServices( - IImageSharpBuilder builder, - Action setupAction) - { - builder.Services.Configure(setupAction); - - builder.Services.AddSingleton(); - - builder.Services.AddSingleton>(); - - builder.SetRequestParser(); - - builder.Services.AddSingleton(); - - builder.SetCache(); - - builder.SetCacheKey(); - - builder.SetCacheHash(); - - builder.AddProvider(); - - builder.AddProcessor() - .AddProcessor() - .AddProcessor() - .AddProcessor() - .AddProcessor(); - - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - builder.AddConverter>(); - - builder.AddConverter(); - builder.AddConverter(); - - builder.Services.AddSingleton(); - } -} diff --git a/src/ImageSharp.Web/FormatUtilities.cs b/src/ImageSharp.Web/FormatUtilities.cs index 928241bf..95c6aaed 100644 --- a/src/ImageSharp.Web/FormatUtilities.cs +++ b/src/ImageSharp.Web/FormatUtilities.cs @@ -17,8 +17,8 @@ namespace SixLabors.ImageSharp.Web; /// public sealed class FormatUtilities { - private readonly List extensions = new(); - private readonly Dictionary extensionsByMimeType = new(); + private readonly List extensions = []; + private readonly Dictionary extensionsByMimeType = []; /// /// Initializes a new instance of the class. @@ -30,7 +30,7 @@ public FormatUtilities(IOptions options) foreach (IImageFormat imageFormat in options.Value.Configuration.ImageFormats) { - string[] extensions = imageFormat.FileExtensions.ToArray(); + string[] extensions = [.. imageFormat.FileExtensions]; this.extensions.AddRange(extensions); diff --git a/src/ImageSharp.Web/FormattedImage.cs b/src/ImageSharp.Web/FormattedImage.cs index d0e47f67..acecbd92 100644 --- a/src/ImageSharp.Web/FormattedImage.cs +++ b/src/ImageSharp.Web/FormattedImage.cs @@ -101,9 +101,6 @@ public IImageEncoder Encoder internal static async Task LoadAsync(DecoderOptions options, Stream source) where TPixel : unmanaged, IPixel { - // TODO: We want to be able to apply decoder options per request. - // For example. If a resize command has been passed with no extra resampling options - // then we should apply those changes on decode. This will allow memory savings and performance improvements. Image image = await Image.LoadAsync(options, source); return new FormattedImage(image, image.Metadata.DecodedImageFormat!, false); } diff --git a/src/ImageSharp.Web/HMACUtilities.cs b/src/ImageSharp.Web/HMACUtilities.cs index e0834780..eb9d4f5f 100644 --- a/src/ImageSharp.Web/HMACUtilities.cs +++ b/src/ImageSharp.Web/HMACUtilities.cs @@ -38,10 +38,8 @@ private enum HashAlgorithmSizes /// The key can be any length. However, the recommended size is 64 bytes. /// /// The hashed . - public static unsafe string ComputeHMACSHA256(string value, byte[] secret) - { - return CreateHMAC(value, secret, HashAlgorithmSizes.HMACSHA256); - } + public static string ComputeHMACSHA256(string value, byte[] secret) + => CreateHMAC(value, secret, HashAlgorithmSizes.HMACSHA256); /// /// Computes a Hash-based Message Authentication Code (HMAC) by using the SHA384 hash function. @@ -52,10 +50,8 @@ public static unsafe string ComputeHMACSHA256(string value, byte[] secret) /// The key can be any length. However, the recommended size is 128 bytes. /// /// The hashed . - public static unsafe string ComputeHMACSHA384(string value, byte[] secret) - { - return CreateHMAC(value, secret, HashAlgorithmSizes.HMACSHA384); - } + public static string ComputeHMACSHA384(string value, byte[] secret) + => CreateHMAC(value, secret, HashAlgorithmSizes.HMACSHA384); /// /// Computes a Hash-based Message Authentication Code (HMAC) by using the SHA512 hash function. @@ -66,13 +62,11 @@ public static unsafe string ComputeHMACSHA384(string value, byte[] secret) /// The key can be any length. However, the recommended size is 128 bytes. /// /// The hashed . - public static unsafe string ComputeHMACSHA512(string value, byte[] secret) - { - return CreateHMAC(value, secret, HashAlgorithmSizes.HMACSHA512); - } + public static string ComputeHMACSHA512(string value, byte[] secret) + => CreateHMAC(value, secret, HashAlgorithmSizes.HMACSHA512); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe string CreateHMAC(string value, ReadOnlySpan secret, HashAlgorithmSizes hashSize) + private static string CreateHMAC(string value, ReadOnlySpan secret, HashAlgorithmSizes hashSize) { int byteCount = Encoding.ASCII.GetByteCount(value); byte[]? buffer = null; @@ -84,23 +78,16 @@ private static unsafe string CreateHMAC(string value, ReadOnlySpan secret, ? stackalloc byte[byteCount] : (buffer = ArrayPool.Shared.Rent(byteCount)).AsSpan(0, byteCount); - Encoding.ASCII.GetBytes(value, bytes); + _ = Encoding.ASCII.GetBytes(value, bytes); // Safe to always stackalloc here. We max out at 64 bytes. Span hash = stackalloc byte[(int)hashSize]; - switch (hashSize) + _ = hashSize switch { - default: - case HashAlgorithmSizes.HMACSHA256: - HMACSHA256.TryHashData(secret, bytes, hash, out _); - break; - case HashAlgorithmSizes.HMACSHA384: - HMACSHA384.TryHashData(secret, bytes, hash, out _); - break; - case HashAlgorithmSizes.HMACSHA512: - HMACSHA512.TryHashData(secret, bytes, hash, out _); - break; - } + HashAlgorithmSizes.HMACSHA384 => HMACSHA384.TryHashData(secret, bytes, hash, out _), + HashAlgorithmSizes.HMACSHA512 => HMACSHA512.TryHashData(secret, bytes, hash, out _), + _ => HMACSHA256.TryHashData(secret, bytes, hash, out _), + }; // Finally encode the hash to make it web safe. return HexEncoder.Encode(hash); diff --git a/src/ImageSharp.Web/DependencyInjection/IImageSharpBuilder.cs b/src/ImageSharp.Web/IImageSharpBuilder.cs similarity index 73% rename from src/ImageSharp.Web/DependencyInjection/IImageSharpBuilder.cs rename to src/ImageSharp.Web/IImageSharpBuilder.cs index f1935af9..c2673a6c 100644 --- a/src/ImageSharp.Web/DependencyInjection/IImageSharpBuilder.cs +++ b/src/ImageSharp.Web/IImageSharpBuilder.cs @@ -1,9 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using Microsoft.Extensions.DependencyInjection; -namespace SixLabors.ImageSharp.Web.DependencyInjection; +namespace SixLabors.ImageSharp.Web; /// /// Defines a contract for adding ImageSharp services. @@ -13,5 +13,5 @@ public interface IImageSharpBuilder /// /// Gets the where ImageSharp services are configured. /// - IServiceCollection Services { get; } + public IServiceCollection Services { get; } } diff --git a/src/ImageSharp.Web/ImageCacheMetadata.cs b/src/ImageSharp.Web/ImageCacheMetadata.cs index fafc4d5e..bdac1d31 100644 --- a/src/ImageSharp.Web/ImageCacheMetadata.cs +++ b/src/ImageSharp.Web/ImageCacheMetadata.cs @@ -97,13 +97,13 @@ public ImageCacheMetadata( public static ImageCacheMetadata FromDictionary(IDictionary dictionary) { // DateTime.TryParse(null) == DateTime.MinValue so no need for conditional; - dictionary.TryGetValue(SourceLastModifiedKey, out string? sourceLastWriteTimeUtcString); - DateTime.TryParse(sourceLastWriteTimeUtcString, null, DateTimeStyles.RoundtripKind, out DateTime sourceLastWriteTimeUtc); + _ = dictionary.TryGetValue(SourceLastModifiedKey, out string? sourceLastWriteTimeUtcString); + _ = DateTime.TryParse(sourceLastWriteTimeUtcString, null, DateTimeStyles.RoundtripKind, out DateTime sourceLastWriteTimeUtc); - dictionary.TryGetValue(CacheLastModifiedKey, out string? cacheLastWriteTimeUtcString); - DateTime.TryParse(cacheLastWriteTimeUtcString, null, DateTimeStyles.RoundtripKind, out DateTime cacheLastWriteTimeUtc); + _ = dictionary.TryGetValue(CacheLastModifiedKey, out string? cacheLastWriteTimeUtcString); + _ = DateTime.TryParse(cacheLastWriteTimeUtcString, null, DateTimeStyles.RoundtripKind, out DateTime cacheLastWriteTimeUtc); - dictionary.TryGetValue(ContentTypeKey, out string? contentType); + _ = dictionary.TryGetValue(ContentTypeKey, out string? contentType); Guard.NotNull(contentType); // int.TryParse(null) == 0 and we want to return TimeSpan.MinValue not TimeSpan.Zero @@ -114,7 +114,7 @@ public static ImageCacheMetadata FromDictionary(IDictionary dict cacheControlMaxAge = TimeSpan.FromSeconds(maxAge); } - dictionary.TryGetValue(ContentLengthKey, out string? contentLengthString); + _ = dictionary.TryGetValue(ContentLengthKey, out string? contentLengthString); _ = long.TryParse(contentLengthString, out long contentLength); return new ImageCacheMetadata( @@ -132,7 +132,7 @@ public static ImageCacheMetadata FromDictionary(IDictionary dict /// The . public static async Task ReadAsync(Stream stream) { - Dictionary dictionary = new(); + Dictionary dictionary = []; using (StreamReader reader = new(stream, Encoding.UTF8)) { string? line; @@ -202,8 +202,17 @@ public async Task WriteAsync(Stream stream) await using StreamWriter writer = new(stream, Encoding.UTF8); foreach (KeyValuePair keyValuePair in dictionary) { - // TODO: string.Create - await writer.WriteLineAsync($"{keyValuePair.Key}:{keyValuePair.Value}"); + string line = string.Create( + keyValuePair.Key.Length + keyValuePair.Value.Length + 1, + keyValuePair, + static (span, state) => + { + state.Key.AsSpan().CopyTo(span); + span[state.Key.Length] = ':'; + state.Value.AsSpan().CopyTo(span[(state.Key.Length + 1)..]); + }); + + await writer.WriteLineAsync(line); } await writer.FlushAsync(); diff --git a/src/ImageSharp.Web/ImageSharp.Web.csproj b/src/ImageSharp.Web/ImageSharp.Web.csproj index ccbd0346..e149431e 100644 --- a/src/ImageSharp.Web/ImageSharp.Web.csproj +++ b/src/ImageSharp.Web/ImageSharp.Web.csproj @@ -1,4 +1,4 @@ - + SixLabors.ImageSharp.Web @@ -20,19 +20,19 @@ - - 3.0 + + 4.0 - net7.0;net6.0 + net8.0;net10.0 - net6.0 + net8.0 @@ -46,7 +46,7 @@ - + diff --git a/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilder.cs b/src/ImageSharp.Web/ImageSharpBuilder.cs similarity index 92% rename from src/ImageSharp.Web/DependencyInjection/ImageSharpBuilder.cs rename to src/ImageSharp.Web/ImageSharpBuilder.cs index 58da1137..303f71ba 100644 --- a/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilder.cs +++ b/src/ImageSharp.Web/ImageSharpBuilder.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; -namespace SixLabors.ImageSharp.Web.DependencyInjection; +namespace SixLabors.ImageSharp.Web; /// /// Allows fine grained configuration of ImageSharp services. diff --git a/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilderExtensions.cs b/src/ImageSharp.Web/ImageSharpBuilderExtensions.cs similarity index 81% rename from src/ImageSharp.Web/DependencyInjection/ImageSharpBuilderExtensions.cs rename to src/ImageSharp.Web/ImageSharpBuilderExtensions.cs index 8c4a17bb..4f17539c 100644 --- a/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilderExtensions.cs +++ b/src/ImageSharp.Web/ImageSharpBuilderExtensions.cs @@ -1,16 +1,18 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using SixLabors.ImageSharp.Web; using SixLabors.ImageSharp.Web.Caching; using SixLabors.ImageSharp.Web.Commands; using SixLabors.ImageSharp.Web.Commands.Converters; using SixLabors.ImageSharp.Web.Processors; using SixLabors.ImageSharp.Web.Providers; -namespace SixLabors.ImageSharp.Web.DependencyInjection; +namespace SixLabors.ImageSharp.Web; /// /// Extension methods for that allow configuration of services. @@ -23,10 +25,10 @@ public static class ImageSharpBuilderExtensions /// The type of class implementing to add. /// The core builder. /// The . - public static IImageSharpBuilder SetRequestParser(this IImageSharpBuilder builder) + public static IImageSharpBuilder SetRequestParser<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TParser>(this IImageSharpBuilder builder) where TParser : class, IRequestParser { - builder.Services.Replace(ServiceDescriptor.Singleton()); + _ = builder.Services.Replace(ServiceDescriptor.Singleton()); return builder; } @@ -39,7 +41,7 @@ public static IImageSharpBuilder SetRequestParser(this IImageSharpBuild /// The . public static IImageSharpBuilder SetRequestParser(this IImageSharpBuilder builder, Func implementationFactory) { - builder.Services.Replace(ServiceDescriptor.Singleton(implementationFactory)); + _ = builder.Services.Replace(ServiceDescriptor.Singleton(implementationFactory)); return builder; } @@ -50,10 +52,10 @@ public static IImageSharpBuilder SetRequestParser(this IImageSharpBuilder builde /// The type of class implementing to add. /// The core builder. /// The . - public static IImageSharpBuilder SetCache(this IImageSharpBuilder builder) + public static IImageSharpBuilder SetCache<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TCache>(this IImageSharpBuilder builder) where TCache : class, IImageCache { - builder.Services.Replace(ServiceDescriptor.Singleton()); + _ = builder.Services.Replace(ServiceDescriptor.Singleton()); return builder; } @@ -66,7 +68,7 @@ public static IImageSharpBuilder SetCache(this IImageSharpBuilder builde /// The . public static IImageSharpBuilder SetCache(this IImageSharpBuilder builder, Func implementationFactory) { - builder.Services.Replace(ServiceDescriptor.Singleton(implementationFactory)); + _ = builder.Services.Replace(ServiceDescriptor.Singleton(implementationFactory)); return builder; } @@ -77,10 +79,10 @@ public static IImageSharpBuilder SetCache(this IImageSharpBuilder builder, Func< /// The type of class implementing to add. /// The core builder. /// The . - public static IImageSharpBuilder SetCacheKey(this IImageSharpBuilder builder) + public static IImageSharpBuilder SetCacheKey<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TCacheKey>(this IImageSharpBuilder builder) where TCacheKey : class, ICacheKey { - builder.Services.Replace(ServiceDescriptor.Singleton()); + _ = builder.Services.Replace(ServiceDescriptor.Singleton()); return builder; } @@ -93,7 +95,7 @@ public static IImageSharpBuilder SetCacheKey(this IImageSharpBuilder /// The . public static IImageSharpBuilder SetCacheKey(this IImageSharpBuilder builder, Func implementationFactory) { - builder.Services.Replace(ServiceDescriptor.Singleton(implementationFactory)); + _ = builder.Services.Replace(ServiceDescriptor.Singleton(implementationFactory)); return builder; } @@ -104,10 +106,10 @@ public static IImageSharpBuilder SetCacheKey(this IImageSharpBuilder builder, Fu /// The type of class implementing to add. /// The core builder. /// The . - public static IImageSharpBuilder SetCacheHash(this IImageSharpBuilder builder) + public static IImageSharpBuilder SetCacheHash<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TCacheHash>(this IImageSharpBuilder builder) where TCacheHash : class, ICacheHash { - builder.Services.Replace(ServiceDescriptor.Singleton()); + _ = builder.Services.Replace(ServiceDescriptor.Singleton()); return builder; } @@ -120,7 +122,7 @@ public static IImageSharpBuilder SetCacheHash(this IImageSharpBuilde /// The . public static IImageSharpBuilder SetCacheHash(this IImageSharpBuilder builder, Func implementationFactory) { - builder.Services.Replace(ServiceDescriptor.Singleton(implementationFactory)); + _ = builder.Services.Replace(ServiceDescriptor.Singleton(implementationFactory)); return builder; } @@ -131,7 +133,7 @@ public static IImageSharpBuilder SetCacheHash(this IImageSharpBuilder builder, F /// The type of class implementing to add. /// The core builder. /// The . - public static IImageSharpBuilder AddProvider(this IImageSharpBuilder builder) + public static IImageSharpBuilder AddProvider<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TProvider>(this IImageSharpBuilder builder) where TProvider : class, IImageProvider { builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); @@ -161,14 +163,14 @@ public static IImageSharpBuilder AddProvider(this IImageSharpBuilder /// The core builder. /// The zero-based index at which the provider should be inserted. /// The . - public static IImageSharpBuilder InsertProvider(this IImageSharpBuilder builder, int index) + public static IImageSharpBuilder InsertProvider<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TProvider>(this IImageSharpBuilder builder, int index) where TProvider : class, IImageProvider { - var descriptors = builder.Services.Where(x => x.ServiceType == typeof(IImageProvider)).ToList(); - descriptors.RemoveAll(x => x.GetImplementationType() == typeof(TProvider)); + List descriptors = [.. builder.Services.Where(x => x.ServiceType == typeof(IImageProvider))]; + _ = descriptors.RemoveAll(x => x.GetImplementationType() == typeof(TProvider)); descriptors.Insert(index, ServiceDescriptor.Singleton()); - builder.ClearProviders(); + _ = builder.ClearProviders(); builder.Services.TryAddEnumerable(descriptors); return builder; @@ -185,11 +187,11 @@ public static IImageSharpBuilder InsertProvider(this IImageSharpBuild public static IImageSharpBuilder InsertProvider(this IImageSharpBuilder builder, int index, Func implementationFactory) where TProvider : class, IImageProvider { - var descriptors = builder.Services.Where(x => x.ServiceType == typeof(IImageProvider)).ToList(); - descriptors.RemoveAll(x => x.GetImplementationType() == typeof(TProvider)); + List descriptors = [.. builder.Services.Where(x => x.ServiceType == typeof(IImageProvider))]; + _ = descriptors.RemoveAll(x => x.GetImplementationType() == typeof(TProvider)); descriptors.Insert(index, ServiceDescriptor.Singleton(implementationFactory)); - builder.ClearProviders(); + _ = builder.ClearProviders(); builder.Services.TryAddEnumerable(descriptors); return builder; @@ -207,7 +209,7 @@ public static IImageSharpBuilder RemoveProvider(this IImageSharpBuild ServiceDescriptor? descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(IImageProvider) && x.GetImplementationType() == typeof(TProvider)); if (descriptor != null) { - builder.Services.Remove(descriptor); + _ = builder.Services.Remove(descriptor); } return builder; @@ -220,7 +222,7 @@ public static IImageSharpBuilder RemoveProvider(this IImageSharpBuild /// The . public static IImageSharpBuilder ClearProviders(this IImageSharpBuilder builder) { - builder.Services.RemoveAll(); + _ = builder.Services.RemoveAll(); return builder; } @@ -231,7 +233,7 @@ public static IImageSharpBuilder ClearProviders(this IImageSharpBuilder builder) /// The type of class implementing to add. /// The core builder. /// The . - public static IImageSharpBuilder AddProcessor(this IImageSharpBuilder builder) + public static IImageSharpBuilder AddProcessor<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(this IImageSharpBuilder builder) where T : class, IImageWebProcessor { builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); @@ -266,7 +268,7 @@ public static IImageSharpBuilder RemoveProcessor(this IImageSharpBui ServiceDescriptor? descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(IImageWebProcessor) && x.GetImplementationType() == typeof(TProcessor)); if (descriptor != null) { - builder.Services.Remove(descriptor); + _ = builder.Services.Remove(descriptor); } return builder; @@ -279,7 +281,7 @@ public static IImageSharpBuilder RemoveProcessor(this IImageSharpBui /// The . public static IImageSharpBuilder ClearProcessors(this IImageSharpBuilder builder) { - builder.Services.RemoveAll(); + _ = builder.Services.RemoveAll(); return builder; } @@ -290,7 +292,7 @@ public static IImageSharpBuilder ClearProcessors(this IImageSharpBuilder builder /// The type of class implementing to add. /// The core builder. /// The . - public static IImageSharpBuilder AddConverter(this IImageSharpBuilder builder) + public static IImageSharpBuilder AddConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TConverter>(this IImageSharpBuilder builder) where TConverter : class, ICommandConverter { builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); @@ -325,7 +327,7 @@ public static IImageSharpBuilder RemoveConverter(this IImageSharpBui ServiceDescriptor? descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(ICommandConverter) && x.GetImplementationType() == typeof(TConverter)); if (descriptor != null) { - builder.Services.Remove(descriptor); + _ = builder.Services.Remove(descriptor); } return builder; @@ -338,7 +340,7 @@ public static IImageSharpBuilder RemoveConverter(this IImageSharpBui /// The . public static IImageSharpBuilder ClearConverters(this IImageSharpBuilder builder) { - builder.Services.RemoveAll(); + _ = builder.Services.RemoveAll(); return builder; } @@ -350,10 +352,12 @@ public static IImageSharpBuilder ClearConverters(this IImageSharpBuilder builder /// The core builder. /// The configuration being bound. /// The . - public static IImageSharpBuilder Configure(this IImageSharpBuilder builder, IConfiguration config) + [RequiresDynamicCode("Binding strongly typed objects to configuration values may require generating dynamic code at runtime.")] + [RequiresUnreferencedCode("TOptions's dependent types may have their members trimmed. Ensure all required members are preserved.")] + public static IImageSharpBuilder Configure<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TOptions>(this IImageSharpBuilder builder, IConfiguration config) where TOptions : class { - builder.Services.Configure(config); + _ = builder.Services.Configure(config); return builder; } @@ -368,7 +372,7 @@ public static IImageSharpBuilder Configure(this IImageSharpBuilder bui public static IImageSharpBuilder Configure(this IImageSharpBuilder builder, Action configureOptions) where TOptions : class { - builder.Services.Configure(configureOptions); + _ = builder.Services.Configure(configureOptions); return builder; } diff --git a/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs b/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs index 6bcde2e0..bfa8ac33 100644 --- a/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs +++ b/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs @@ -160,8 +160,8 @@ public ImageSharpMiddleware( this.next = next; this.options = options.Value; this.requestParser = requestParser; - this.providers = resolvers as IImageProvider[] ?? resolvers.ToArray(); - this.processors = processors as IImageWebProcessor[] ?? processors.ToArray(); + this.providers = resolvers as IImageProvider[] ?? [.. resolvers]; + this.processors = processors as IImageWebProcessor[] ?? [.. processors]; this.cache = cache; this.cacheKey = cacheKey; this.cacheHash = cacheHash; @@ -344,7 +344,6 @@ private async Task ProcessRequestAsync( await using (Stream inStream = await sourceImageResolver.OpenReadAsync()) { - // TODO: Do we need some way to set options based upon processors? DecoderOptions decoderOptions = await this.options.OnBeforeLoadAsync.Invoke(imageCommandContext, this.options.Configuration) ?? new() { Configuration = this.options.Configuration }; @@ -369,7 +368,7 @@ private async Task ProcessRequestAsync( image = await FormattedImage.LoadAsync(decoderOptions, inStream); } - image.Process( + _ = image.Process( this.logger, sortedProcessors, commands, @@ -407,7 +406,7 @@ private async Task ProcessRequestAsync( // Remove any resolver from the cache so we always resolve next request // for the same key. - CacheResolverLru.TryRemove(key); + _ = CacheResolverLru.TryRemove(key); readResult = new ImageWorkerResult(cachedImageMetadata, null); } @@ -469,7 +468,7 @@ private async Task IsNewOrUpdatedAsync( if (cachedImage.ImageCacheResolver is null) { // Remove the null resolver from the store. - CacheResolverLru.TryRemove(key); + _ = CacheResolverLru.TryRemove(key); return new ImageWorkerResult(sourceImageMetadata); } @@ -481,7 +480,7 @@ private async Task IsNewOrUpdatedAsync( || cachedImage.ImageCacheMetadata.SourceLastWriteTimeUtc != sourceImageMetadata.LastWriteTimeUtc) { // We want to remove the resolver from the store so that the next check gets the updated file. - CacheResolverLru.TryRemove(key); + _ = CacheResolverLru.TryRemove(key); return new ImageWorkerResult(sourceImageMetadata); } @@ -534,7 +533,7 @@ private async Task SendResponseAsync( // The image has failed to be returned from the cache. // This can happen if the cached image has been physically deleted but the item is still in the LRU cache. // We'll retry running the request again in it's entirety. This ensures any changes to the source are tracked also. - CacheResolverLru.TryRemove(key); + _ = CacheResolverLru.TryRemove(key); await this.Invoke(httpContext, true); return; } diff --git a/src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs b/src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs index fa4c21e6..8653d4d4 100644 --- a/src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs +++ b/src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs @@ -81,7 +81,7 @@ public class ImageSharpMiddlewareOptions /// /// The key can be any length. However, the recommended size is at least 64 bytes. If the length is zero then no authentication is performed. /// - public byte[] HMACSecretKey { get; set; } = Array.Empty(); + public byte[] HMACSecretKey { get; set; } = []; /// /// Gets or sets the method used to compute a Hash-based Message Authentication Code (HMAC) for request authentication. diff --git a/src/ImageSharp.Web/Middleware/LoggerExtensions.cs b/src/ImageSharp.Web/Middleware/LoggerExtensions.cs index 7f158e8a..0b2b0676 100644 --- a/src/ImageSharp.Web/Middleware/LoggerExtensions.cs +++ b/src/ImageSharp.Web/Middleware/LoggerExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using Microsoft.Extensions.Logging; @@ -54,9 +54,7 @@ static LoggerExtensions() /// The full request uri. /// The captured exception. public static void LogImageProcessingFailed(this ILogger logger, string uri, Exception exception) - { - LogProcessingErrorAction(logger, uri, exception); - } + => LogProcessingErrorAction(logger, uri, exception); /// /// Logs that a given image could not be resolved. @@ -64,9 +62,7 @@ public static void LogImageProcessingFailed(this ILogger logger, string uri, Exc /// The type used to perform logging. /// The full request uri. public static void LogImageResolveFailed(this ILogger logger, string uri) - { - LogResolveFailedAction(logger, uri, null); - } + => LogResolveFailedAction(logger, uri, null); /// /// Logs that a given image request has been served. @@ -75,9 +71,7 @@ public static void LogImageResolveFailed(this ILogger logger, string uri) /// The full request uri. /// The cached image key. public static void LogImageServed(this ILogger logger, string uri, string key) - { - LogServedAction(logger, uri, key, null); - } + => LogServedAction(logger, uri, key, null); /// /// Logs that a given image request has not been modified. @@ -85,9 +79,7 @@ public static void LogImageServed(this ILogger logger, string uri, string key) /// The type used to perform logging. /// The full request uri. public static void LogImageNotModified(this ILogger logger, string uri) - { - LogPathNotModifiedAction(logger, uri, null); - } + => LogPathNotModifiedAction(logger, uri, null); /// /// Logs that access to a given image request has been denied. @@ -95,7 +87,5 @@ public static void LogImageNotModified(this ILogger logger, string uri) /// The type used to perform logging. /// The full request uri. public static void LogImagePreconditionFailed(this ILogger logger, string uri) - { - LogPreconditionFailedAction(logger, uri, null); - } + => LogPreconditionFailedAction(logger, uri, null); } diff --git a/src/ImageSharp.Web/PathUtilities.cs b/src/ImageSharp.Web/PathUtilities.cs index 719b2e27..7e02d907 100644 --- a/src/ImageSharp.Web/PathUtilities.cs +++ b/src/ImageSharp.Web/PathUtilities.cs @@ -15,7 +15,7 @@ internal static class PathUtilities internal static string EnsureTrailingSlash(string path) { if (!string.IsNullOrEmpty(path) && - path[path.Length - 1] != Path.DirectorySeparatorChar) + path[^1] != Path.DirectorySeparatorChar) { return path + Path.DirectorySeparatorChar; } diff --git a/src/ImageSharp.Web/Processors/IImageWebProcessor.cs b/src/ImageSharp.Web/Processors/IImageWebProcessor.cs index df0cdb22..f5d27825 100644 --- a/src/ImageSharp.Web/Processors/IImageWebProcessor.cs +++ b/src/ImageSharp.Web/Processors/IImageWebProcessor.cs @@ -15,7 +15,7 @@ public interface IImageWebProcessor /// /// Gets the collection of recognized command keys. /// - IEnumerable Commands { get; } + public IEnumerable Commands { get; } /// /// Processes the image based on the given commands. @@ -28,7 +28,7 @@ public interface IImageWebProcessor /// The to use as the current parsing culture. /// /// The . - FormattedImage Process( + public FormattedImage Process( FormattedImage image, ILogger logger, CommandCollection commands, @@ -48,5 +48,5 @@ FormattedImage Process( /// The to use as the current parsing culture. /// /// The indicating whether a 32 bit True Color pixel format is required. - bool RequiresTrueColorPixelFormat(CommandCollection commands, CommandParser parser, CultureInfo culture); + public bool RequiresTrueColorPixelFormat(CommandCollection commands, CommandParser parser, CultureInfo culture); } diff --git a/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs b/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs index 4004bfba..ebe44123 100644 --- a/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs +++ b/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs @@ -264,7 +264,7 @@ private static ushort GetExifOrientation(FormattedImage image, CommandCollection return ExifOrientationMode.Unknown; } - image.TryGetExifOrientation(out ushort orientation); + _ = image.TryGetExifOrientation(out ushort orientation); return orientation; } diff --git a/src/ImageSharp.Web/Processors/WebProcessingExtensions.cs b/src/ImageSharp.Web/Processors/WebProcessingExtensions.cs index ada16b3d..4f0bba55 100644 --- a/src/ImageSharp.Web/Processors/WebProcessingExtensions.cs +++ b/src/ImageSharp.Web/Processors/WebProcessingExtensions.cs @@ -50,11 +50,11 @@ public static FormattedImage Process( /// public static IReadOnlyList<(int Index, IImageWebProcessor Processor)> OrderBySupportedCommands(this IEnumerable processors, CommandCollection commands) { - List<(int Index, IImageWebProcessor Processor)> indexedProcessors = new(); + List<(int Index, IImageWebProcessor Processor)> indexedProcessors = []; foreach (IImageWebProcessor processor in processors) { // Get index of first supported command - int index = commands.FindIndex(c => processor.IsSupportedCommand(c)); + int index = commands.FindIndex(processor.IsSupportedCommand); if (index != -1) { indexedProcessors.Add((index, processor)); diff --git a/src/ImageSharp.Web/Providers/IImageProvider.cs b/src/ImageSharp.Web/Providers/IImageProvider.cs index 6de0c68d..b291e765 100644 --- a/src/ImageSharp.Web/Providers/IImageProvider.cs +++ b/src/ImageSharp.Web/Providers/IImageProvider.cs @@ -14,12 +14,12 @@ public interface IImageProvider /// /// Gets the processing behavior. /// - ProcessingBehavior ProcessingBehavior { get; } + public ProcessingBehavior ProcessingBehavior { get; } /// /// Gets or sets the method used by the resolver to identify itself as the correct resolver to use. /// - Func Match { get; set; } + public Func Match { get; set; } /// /// Gets a value indicating whether the current request passes sanitizing rules. @@ -28,12 +28,12 @@ public interface IImageProvider /// /// The /// - bool IsValidRequest(HttpContext context); + public bool IsValidRequest(HttpContext context); /// /// Gets the image resolver associated with the context. /// /// The current HTTP request context. /// The . - Task GetAsync(HttpContext context); + public Task GetAsync(HttpContext context); } diff --git a/src/ImageSharp.Web/RequestAuthorizationUtilities.cs b/src/ImageSharp.Web/RequestAuthorizationUtilities.cs index 970a2e89..8876689a 100644 --- a/src/ImageSharp.Web/RequestAuthorizationUtilities.cs +++ b/src/ImageSharp.Web/RequestAuthorizationUtilities.cs @@ -62,7 +62,7 @@ public RequestAuthorizationUtilities( { foreach (string command in processor.Commands) { - commands.Add(command); + _ = commands.Add(command); } } @@ -78,7 +78,7 @@ public void StripUnknownCommands(CommandCollection commands) if (commands?.Count > 0) { // Strip out any unknown commands, if needed. - List keys = new(commands.Keys); + List keys = [.. commands.Keys]; for (int i = keys.Count - 1; i >= 0; i--) { if (!this.knownCommands.Contains(keys[i])) @@ -207,7 +207,7 @@ private static void ToComponents( } } - private HttpContext ToHttpContext(HostString host, PathString path, QueryString queryString, QueryCollection query) + private DefaultHttpContext ToHttpContext(HostString host, PathString path, QueryString queryString, QueryCollection query) { DefaultHttpContext context = new() { RequestServices = this.serviceProvider }; HttpRequest request = context.Request; diff --git a/src/ImageSharp.Web/Resolvers/IImageCacheResolver.cs b/src/ImageSharp.Web/Resolvers/IImageCacheResolver.cs index b629bb86..8ac95a72 100644 --- a/src/ImageSharp.Web/Resolvers/IImageCacheResolver.cs +++ b/src/ImageSharp.Web/Resolvers/IImageCacheResolver.cs @@ -12,11 +12,11 @@ public interface IImageCacheResolver /// Asynchronously gets metadata associated with this image. /// /// The . - Task GetMetaDataAsync(); + public Task GetMetaDataAsync(); /// /// Asynchronously gets the input image stream. /// /// The . - Task OpenReadAsync(); + public Task OpenReadAsync(); } diff --git a/src/ImageSharp.Web/Resolvers/IImageResolver.cs b/src/ImageSharp.Web/Resolvers/IImageResolver.cs index 72d6dfb0..55730536 100644 --- a/src/ImageSharp.Web/Resolvers/IImageResolver.cs +++ b/src/ImageSharp.Web/Resolvers/IImageResolver.cs @@ -12,11 +12,11 @@ public interface IImageResolver /// Asynchronously gets metadata associated with this image. /// /// The . - Task GetMetaDataAsync(); + public Task GetMetaDataAsync(); /// /// Asynchronously gets the input image stream. /// /// The . - Task OpenReadAsync(); + public Task OpenReadAsync(); } diff --git a/src/ImageSharp.Web/ServiceCollectionExtensions.cs b/src/ImageSharp.Web/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..1b758add --- /dev/null +++ b/src/ImageSharp.Web/ServiceCollectionExtensions.cs @@ -0,0 +1,125 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using Microsoft.Extensions.DependencyInjection; +using SixLabors.ImageSharp.Web; +using SixLabors.ImageSharp.Web.Caching; +using SixLabors.ImageSharp.Web.Commands; +using SixLabors.ImageSharp.Web.Commands.Converters; +using SixLabors.ImageSharp.Web.Middleware; +using SixLabors.ImageSharp.Web.Processors; +using SixLabors.ImageSharp.Web.Providers; +using SixLabors.ImageSharp.Web.Synchronization; + +namespace SixLabors.ImageSharp.Web; + +/// +/// Extension methods for to simplify middleware service registration. +/// +public static class ServiceCollectionExtensions +{ + /// + /// Adds ImageSharp services to the specified with the default options. + /// + /// The to add services to. + /// An that can be used to further configure the ImageSharp services. + public static IImageSharpBuilder AddImageSharp(this IServiceCollection services) + => AddImageSharp(services, _ => { }); + + /// + /// Adds ImageSharp services to the specified with the given options. + /// + /// The to add services to. + /// An to configure the provided . + /// An that can be used to further configure the ImageSharp services. + public static IImageSharpBuilder AddImageSharp( + this IServiceCollection services, + Action setupAction) + { + Guard.NotNull(services, nameof(services)); + Guard.NotNull(setupAction, nameof(setupAction)); + + IImageSharpBuilder builder = new ImageSharpBuilder(services); + + AddDefaultServices(builder, setupAction); + + return builder; + } + + private static void AddDefaultServices( + IImageSharpBuilder builder, + Action setupAction) + { + _ = builder.Services.Configure(setupAction); + + _ = builder.Services.AddSingleton(); + + _ = builder.Services.AddSingleton>(); + + _ = builder.SetRequestParser(); + + _ = builder.Services.AddSingleton(); + + _ = builder.SetCache(); + + _ = builder.SetCacheKey(); + + _ = builder.SetCacheHash(); + + _ = builder.AddProvider(); + + _ = builder.AddProcessor() + .AddProcessor() + .AddProcessor() + .AddProcessor() + .AddProcessor(); + + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + _ = builder.AddConverter>(); + + _ = builder.AddConverter(); + _ = builder.AddConverter(); + + _ = builder.Services.AddSingleton(); + } +} diff --git a/src/ImageSharp.Web/Synchronization/AsyncKeyLock.cs b/src/ImageSharp.Web/Synchronization/AsyncKeyLock.cs index 13cd5b95..c6a98349 100644 --- a/src/ImageSharp.Web/Synchronization/AsyncKeyLock.cs +++ b/src/ImageSharp.Web/Synchronization/AsyncKeyLock.cs @@ -25,7 +25,7 @@ public sealed class AsyncKeyLock : IDisposable /// The maximum number of locks that should be pooled for reuse. public AsyncKeyLock(int maxPoolSize = 64) { - this.pool = new ConcurrentBag(); + this.pool = []; this.activeLocks = new RefCountedConcurrentDictionary(this.CreateLeasedLock, this.ReturnLeasedLock); this.maxPoolSize = maxPoolSize; } diff --git a/src/ImageSharp.Web/Synchronization/AsyncKeyReaderWriterLock.cs b/src/ImageSharp.Web/Synchronization/AsyncKeyReaderWriterLock.cs index 94557389..894fd67d 100644 --- a/src/ImageSharp.Web/Synchronization/AsyncKeyReaderWriterLock.cs +++ b/src/ImageSharp.Web/Synchronization/AsyncKeyReaderWriterLock.cs @@ -25,7 +25,7 @@ public class AsyncKeyReaderWriterLock /// The maximum number of locks that should be pooled for reuse. public AsyncKeyReaderWriterLock(int maxPoolSize = 64) { - this.pool = new ConcurrentBag(); + this.pool = []; this.activeLocks = new RefCountedConcurrentDictionary(this.CreateLeasedLock, this.ReturnLeasedLock); this.maxPoolSize = maxPoolSize; } diff --git a/src/ImageSharp.Web/TagHelpers/ImageTagHelper.cs b/src/ImageSharp.Web/TagHelpers/ImageTagHelper.cs index cf7c675e..8f402b18 100644 --- a/src/ImageSharp.Web/TagHelpers/ImageTagHelper.cs +++ b/src/ImageSharp.Web/TagHelpers/ImageTagHelper.cs @@ -198,7 +198,7 @@ public override void Process(TagHelperContext context, TagHelperOutput output) output.CopyHtmlAttribute(SrcAttributeName, context); this.ProcessUrlAttribute(SrcAttributeName, output); - CommandCollection commands = new(); + CommandCollection commands = []; this.AddProcessingCommands(context, output, commands, this.parserCulture); if (commands.Count > 0) diff --git a/tests/ImageSharp.Web.Benchmarks/Caching/CacheHashBaseline.cs b/tests/ImageSharp.Web.Benchmarks/Caching/CacheHashBaseline.cs index f91b3239..9c21dabf 100644 --- a/tests/ImageSharp.Web.Benchmarks/Caching/CacheHashBaseline.cs +++ b/tests/ImageSharp.Web.Benchmarks/Caching/CacheHashBaseline.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Globalization; using System.Security.Cryptography; using System.Text; using SixLabors.ImageSharp.Web.Caching; @@ -20,18 +21,15 @@ public string Create(string value, uint length) // { // throw new ArgumentOutOfRangeException(nameof(length), $"Value must be greater than or equal to {2} and less than or equal to {64}."); // } - using (var hashAlgorithm = SHA256.Create()) + // Concatenate the hash bytes into one long string. + int len = (int)length; + byte[] hash = SHA256.HashData(Encoding.ASCII.GetBytes(value)); + StringBuilder sb = new(len); + for (int i = 0; i < len / 2; i++) { - // Concatenate the hash bytes into one long string. - int len = (int)length; - byte[] hash = hashAlgorithm.ComputeHash(Encoding.ASCII.GetBytes(value)); - var sb = new StringBuilder(len); - for (int i = 0; i < len / 2; i++) - { - sb.Append(hash[i].ToString("X2")); - } - - return sb.ToString(); + sb.Append(hash[i].ToString("X2", CultureInfo.InvariantCulture)); } + + return sb.ToString(); } } diff --git a/tests/ImageSharp.Web.Benchmarks/Caching/CacheHashBenchmarks.cs b/tests/ImageSharp.Web.Benchmarks/Caching/CacheHashBenchmarks.cs index 3e816a73..c6d3438c 100644 --- a/tests/ImageSharp.Web.Benchmarks/Caching/CacheHashBenchmarks.cs +++ b/tests/ImageSharp.Web.Benchmarks/Caching/CacheHashBenchmarks.cs @@ -13,8 +13,8 @@ public class CacheHashBenchmarks { private const string URL = "http://testwebsite.com/image-12345.jpeg?width=400"; private static readonly IOptions MWOptions = Options.Create(new ImageSharpMiddlewareOptions()); - private static readonly SHA256CacheHash Sha256Hasher = new SHA256CacheHash(MWOptions); - private static readonly CacheHashBaseline NaiveSha256Hasher = new CacheHashBaseline(); + private static readonly SHA256CacheHash Sha256Hasher = new(MWOptions); + private static readonly CacheHashBaseline NaiveSha256Hasher = new(); [Benchmark(Baseline = true, Description = "Baseline Sha256Hasher")] public string HashUsingBaselineHash() => NaiveSha256Hasher.Create(URL, 12); diff --git a/tests/ImageSharp.Web.Benchmarks/Caching/CacheKeyBenchmarks.cs b/tests/ImageSharp.Web.Benchmarks/Caching/CacheKeyBenchmarks.cs index b04d5fb6..96238e36 100644 --- a/tests/ImageSharp.Web.Benchmarks/Caching/CacheKeyBenchmarks.cs +++ b/tests/ImageSharp.Web.Benchmarks/Caching/CacheKeyBenchmarks.cs @@ -17,11 +17,11 @@ public class CacheKeyBenchmarks { "width", "400" } }; - private static readonly ICacheKey LegacyV1CacheKey = new LegacyV1CacheKey(); - private static readonly ICacheKey UriRelativeCacheKey = new UriRelativeCacheKey(); - private static readonly ICacheKey UriAbsoluteCacheKey = new UriAbsoluteCacheKey(); - private static readonly ICacheKey UriRelativeLowerInvariantCacheKey = new UriRelativeLowerInvariantCacheKey(); - private static readonly ICacheKey UriAbsoluteLowerInvariantCacheKey = new UriAbsoluteLowerInvariantCacheKey(); + private static readonly LegacyV1CacheKey LegacyV1CacheKey = new(); + private static readonly UriRelativeCacheKey UriRelativeCacheKey = new(); + private static readonly UriAbsoluteCacheKey UriAbsoluteCacheKey = new(); + private static readonly UriRelativeLowerInvariantCacheKey UriRelativeLowerInvariantCacheKey = new(); + private static readonly UriAbsoluteLowerInvariantCacheKey UriAbsoluteLowerInvariantCacheKey = new(); [Benchmark(Baseline = true, Description = nameof(LegacyV1CacheKey))] public string CreateUsingBaseline() => LegacyV1CacheKey.Create(Context, Commands); @@ -55,9 +55,9 @@ public class CacheKeyBenchmarks | UriAbsoluteLowerInvariantCacheKey | 475.4 ns | 4.18 ns | 3.71 ns | 0.71 | 0.02 | 0.0763 | 320 B | */ - private static HttpContext CreateContext() + private static DefaultHttpContext CreateContext() { - var httpContext = new DefaultHttpContext(); + DefaultHttpContext httpContext = new(); httpContext.Request.Scheme = Uri.UriSchemeHttp; httpContext.Request.Host = new HostString("testwebsite.com"); httpContext.Request.PathBase = "/images"; diff --git a/tests/ImageSharp.Web.Benchmarks/Caching/StringJoinBenchmarks.cs b/tests/ImageSharp.Web.Benchmarks/Caching/StringJoinBenchmarks.cs index 775d705d..b01dcca4 100644 --- a/tests/ImageSharp.Web.Benchmarks/Caching/StringJoinBenchmarks.cs +++ b/tests/ImageSharp.Web.Benchmarks/Caching/StringJoinBenchmarks.cs @@ -26,7 +26,7 @@ public string JoinUsingStringBuilder() const char separator = '/'; // Each key substring char + separator + key - var sb = new StringBuilder((this.CacheFolderDepth * 2) + Key.Length); + StringBuilder sb = new StringBuilder((this.CacheFolderDepth * 2) + Key.Length); ReadOnlySpan paths = keySpan.Slice(0, this.CacheFolderDepth); for (int i = 0; i < paths.Length; i++) { diff --git a/tests/ImageSharp.Web.Benchmarks/Caching/ToHexBenchmarks.cs b/tests/ImageSharp.Web.Benchmarks/Caching/ToHexBenchmarks.cs index ec6ec7b2..baf2fafa 100644 --- a/tests/ImageSharp.Web.Benchmarks/Caching/ToHexBenchmarks.cs +++ b/tests/ImageSharp.Web.Benchmarks/Caching/ToHexBenchmarks.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Globalization; using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; @@ -18,10 +19,10 @@ public class ToHexBenchmarks public string StringBuilderToHex() { const int len = 12; - var sb = new StringBuilder(len); + StringBuilder sb = new(len); for (int i = 0; i < len / 2; i++) { - sb.Append(Bytes[i].ToString("x2")); + sb.Append(Bytes[i].ToString("x2", CultureInfo.InvariantCulture)); } return sb.ToString(); @@ -52,19 +53,16 @@ public string CustomToHex() } [Benchmark(Description = "HexEncoder.Encode with LUT")] - public string CustomToHexUnsafe() => HexEncoder.Encode(new Span(Bytes).Slice(0, 6)); + public string CustomToHexUnsafe() => HexEncoder.Encode(new Span(Bytes)[..6]); private static byte[] Hash() { - using (var hashAlgorithm = SHA256.Create()) - { - // Concatenate the hash bytes into one long string. - string value = "http://testwebsite.com/image-12345.jpeg?width=400"; - int byteCount = Encoding.ASCII.GetByteCount(value); - byte[] buffer = new byte[byteCount]; - Encoding.ASCII.GetBytes(value, 0, value.Length, buffer, 0); - return hashAlgorithm.ComputeHash(buffer, 0, byteCount); - } + // Concatenate the hash bytes into one long string. + string value = "http://testwebsite.com/image-12345.jpeg?width=400"; + int byteCount = Encoding.ASCII.GetByteCount(value); + byte[] buffer = new byte[byteCount]; + Encoding.ASCII.GetBytes(value, 0, value.Length, buffer, 0); + return SHA256.HashData(buffer.AsSpan(0, byteCount)); } /* diff --git a/tests/ImageSharp.Web.Benchmarks/ImageSharp.Web.Benchmarks.csproj b/tests/ImageSharp.Web.Benchmarks/ImageSharp.Web.Benchmarks.csproj index e1db5d1a..8912cfb8 100644 --- a/tests/ImageSharp.Web.Benchmarks/ImageSharp.Web.Benchmarks.csproj +++ b/tests/ImageSharp.Web.Benchmarks/ImageSharp.Web.Benchmarks.csproj @@ -1,4 +1,4 @@ - + Exe @@ -9,15 +9,26 @@ false + + + + + + CA1822;CA1001 + + - net7.0;net6.0 + net8.0;net10.0 - net6.0 + net8.0 diff --git a/tests/ImageSharp.Web.Tests/Caching/CacheHashTests.cs b/tests/ImageSharp.Web.Tests/Caching/CacheHashTests.cs index ea2f4d25..fcca1041 100644 --- a/tests/ImageSharp.Web.Tests/Caching/CacheHashTests.cs +++ b/tests/ImageSharp.Web.Tests/Caching/CacheHashTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Globalization; using System.Text; using Microsoft.Extensions.Options; using SixLabors.ImageSharp.Web.Caching; @@ -12,14 +13,14 @@ namespace SixLabors.ImageSharp.Web.Tests.Caching; public class CacheHashTests { private static readonly IOptions Options = MSOptions.Create(new ImageSharpMiddlewareOptions()); - private static readonly ICacheHash CacheHash = new SHA256CacheHash(Options); + private static readonly SHA256CacheHash CacheHash = new(Options); [Fact] public void CacheHashProducesIdenticalResults() { - const string Input = "http://testwebsite.com/image-12345.jpeg?width=400"; - string expected = CacheHash.Create(Input, 8); - string actual = CacheHash.Create(Input, 8); + const string input = "http://testwebsite.com/image-12345.jpeg?width=400"; + string expected = CacheHash.Create(input, 8); + string actual = CacheHash.Create(input, 8); Assert.Equal(expected, actual); } @@ -27,10 +28,10 @@ public void CacheHashProducesIdenticalResults() [Fact] public void CacheHashProducesDifferentResults() { - const string Input = "http://testwebsite.com/image-12345.jpeg?width=400"; - const string Input2 = "http://testwebsite.com/image-23456.jpeg?width=400"; - string expected = CacheHash.Create(Input, 8); - string actual = CacheHash.Create(Input2, 8); + const string input = "http://testwebsite.com/image-12345.jpeg?width=400"; + const string input2 = "http://testwebsite.com/image-23456.jpeg?width=400"; + string expected = CacheHash.Create(input, 8); + string actual = CacheHash.Create(input2, 8); Assert.NotEqual(expected, actual); } @@ -38,28 +39,28 @@ public void CacheHashProducesDifferentResults() [Fact] public void CacheHashLengthIsIdentical() { - const int Length = 12; - const string Input = "http://testwebsite.com/image-12345.jpeg?width=400"; - const string Input2 = "http://testwebsite.com/image-12345.jpeg"; + const int length = 12; + const string input = "http://testwebsite.com/image-12345.jpeg?width=400"; + const string input2 = "http://testwebsite.com/image-12345.jpeg"; string input3 = CreateLongString(); - int expected = CacheHash.Create(Input, Length).Length; - int actual = CacheHash.Create(Input2, Length).Length; - int actual2 = CacheHash.Create(input3, Length).Length; + int expected = CacheHash.Create(input, length).Length; + int actual = CacheHash.Create(input2, length).Length; + int actual2 = CacheHash.Create(input3, length).Length; Assert.Equal(expected, actual); - Assert.Equal(Length, actual); - Assert.Equal(Length, actual2); + Assert.Equal(length, actual); + Assert.Equal(length, actual2); } private static string CreateLongString() { - const int Length = 2048; - var sb = new StringBuilder(Length); + const int length = 2048; + StringBuilder sb = new(length); - for (int i = 0; i < Length; i++) + for (int i = 0; i < length; i++) { - sb.Append(i.ToString()); + sb.Append(i.ToString(CultureInfo.InvariantCulture)); } return sb.ToString(); diff --git a/tests/ImageSharp.Web.Tests/Caching/CacheKeyTests.cs b/tests/ImageSharp.Web.Tests/Caching/CacheKeyTests.cs index 90317b67..2d82b596 100644 --- a/tests/ImageSharp.Web.Tests/Caching/CacheKeyTests.cs +++ b/tests/ImageSharp.Web.Tests/Caching/CacheKeyTests.cs @@ -9,17 +9,17 @@ namespace SixLabors.ImageSharp.Web.Tests.Caching; public class CacheKeyTests { - private static readonly ICacheKey LegacyV1CacheKey = new LegacyV1CacheKey(); - private static readonly ICacheKey UriRelativeCacheKey = new UriRelativeCacheKey(); - private static readonly ICacheKey UriAbsoluteCacheKey = new UriAbsoluteCacheKey(); - private static readonly ICacheKey UriRelativeLowerInvariantCacheKey = new UriRelativeLowerInvariantCacheKey(); - private static readonly ICacheKey UriAbsoluteLowerInvariantCacheKey = new UriAbsoluteLowerInvariantCacheKey(); + private static readonly LegacyV1CacheKey LegacyV1CacheKey = new(); + private static readonly UriRelativeCacheKey UriRelativeCacheKey = new(); + private static readonly UriAbsoluteCacheKey UriAbsoluteCacheKey = new(); + private static readonly UriRelativeLowerInvariantCacheKey UriRelativeLowerInvariantCacheKey = new(); + private static readonly UriAbsoluteLowerInvariantCacheKey UriAbsoluteLowerInvariantCacheKey = new(); [Fact] public void UriRelativeCacheKey_Is_Relative() { HttpContext context = CreateHttpContext(); - var commands = new CommandCollection() + CommandCollection commands = new() { { "Width", "400" } }; @@ -34,7 +34,7 @@ public void UriRelativeCacheKey_Is_Relative() public void UriRelativeLowerInvariantCacheKey_Is_RelativeAndLowercase() { HttpContext context = CreateHttpContext(); - var commands = new CommandCollection() + CommandCollection commands = new() { { "Width", "400" } }; @@ -49,7 +49,7 @@ public void UriRelativeLowerInvariantCacheKey_Is_RelativeAndLowercase() public void UriAbsoluteCacheKey_Is_Absolute() { HttpContext context = CreateHttpContext(); - var commands = new CommandCollection() + CommandCollection commands = new() { { "Width", "400" } }; @@ -64,7 +64,7 @@ public void UriAbsoluteCacheKey_Is_Absolute() public void UriAbsoluteLowerInvariantCacheKey_Is_AbsoluteAndLowercase() { HttpContext context = CreateHttpContext(); - var commands = new CommandCollection() + CommandCollection commands = new() { { "Width", "400" } }; @@ -79,7 +79,7 @@ public void UriAbsoluteLowerInvariantCacheKey_Is_AbsoluteAndLowercase() public void LegacyV1CacheKey_Matches_V1_Behavior() { HttpContext context = CreateHttpContext(); - var commands = new CommandCollection() + CommandCollection commands = new() { { "Width", "400" } }; @@ -90,9 +90,9 @@ public void LegacyV1CacheKey_Matches_V1_Behavior() Assert.Equal(expected, actual); } - private static HttpContext CreateHttpContext() + private static DefaultHttpContext CreateHttpContext() { - var httpContext = new DefaultHttpContext(); + DefaultHttpContext httpContext = new(); httpContext.Request.Scheme = Uri.UriSchemeHttp; httpContext.Request.Host = new HostString("Testwebsite.com"); httpContext.Request.PathBase = "/Images"; diff --git a/tests/ImageSharp.Web.Tests/Caching/HexEncoderTests.cs b/tests/ImageSharp.Web.Tests/Caching/HexEncoderTests.cs index 21eb5203..de513fb7 100644 --- a/tests/ImageSharp.Web.Tests/Caching/HexEncoderTests.cs +++ b/tests/ImageSharp.Web.Tests/Caching/HexEncoderTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Globalization; using System.Security.Cryptography; using System.Text; using SixLabors.ImageSharp.Web.Caching; @@ -13,10 +14,10 @@ public class HexEncoderTests public void HexEncoderOutputIsCorrect() { byte[] hash = Hash(); - var sb = new StringBuilder(hash.Length * 2); + StringBuilder sb = new(hash.Length * 2); for (int i = 0; i < hash.Length; i++) { - sb.Append(hash[i].ToString("x2")); + sb.Append(hash[i].ToString("x2", CultureInfo.InvariantCulture)); } string expected = sb.ToString(); @@ -27,14 +28,11 @@ public void HexEncoderOutputIsCorrect() private static byte[] Hash() { - using (var hashAlgorithm = SHA256.Create()) - { - // Concatenate the hash bytes into one long string. - const string Value = "http://testwebsite.com/image-12345.jpeg?width=400"; - int byteCount = Encoding.ASCII.GetByteCount(Value); - byte[] buffer = new byte[byteCount]; - Encoding.ASCII.GetBytes(Value, 0, Value.Length, buffer, 0); - return hashAlgorithm.ComputeHash(buffer, 0, byteCount); - } + // Concatenate the hash bytes into one long string. + const string value = "http://testwebsite.com/image-12345.jpeg?width=400"; + int byteCount = Encoding.ASCII.GetByteCount(value); + byte[] buffer = new byte[byteCount]; + Encoding.ASCII.GetBytes(value, 0, value.Length, buffer, 0); + return SHA256.HashData(buffer.AsSpan(0, byteCount)); } } diff --git a/tests/ImageSharp.Web.Tests/Caching/ImageCacheMetadataTests.cs b/tests/ImageSharp.Web.Tests/Caching/ImageCacheMetadataTests.cs index 93358615..72c7ad19 100644 --- a/tests/ImageSharp.Web.Tests/Caching/ImageCacheMetadataTests.cs +++ b/tests/ImageSharp.Web.Tests/Caching/ImageCacheMetadataTests.cs @@ -7,8 +7,8 @@ namespace SixLabors.ImageSharp.Web.Tests.Caching; public class ImageCacheMetaDataTests { - private static readonly DateTime SourceLastWriteTimeUtc = new DateTime(1980, 11, 3); - private static readonly DateTime CacheLastWriteTimeUtc = new DateTime(1980, 11, 4); + private static readonly DateTime SourceLastWriteTimeUtc = new(1980, 11, 3); + private static readonly DateTime CacheLastWriteTimeUtc = new(1980, 11, 4); private static readonly TimeSpan MaxAge = TimeSpan.FromDays(7); private const string ContentType = "image/jpeg"; private const long ContentLength = 1234; @@ -20,7 +20,7 @@ public class ImageCacheMetaDataTests [Fact] public void ConstructorAssignsProperties() { - var meta = new ImageCacheMetadata( + ImageCacheMetadata meta = new( SourceLastWriteTimeUtc, CacheLastWriteTimeUtc, ContentType, @@ -37,13 +37,13 @@ public void ConstructorAssignsProperties() [Fact] public void EqualityChecksAreCorrect() { - var meta = new ImageCacheMetadata( + ImageCacheMetadata meta = new( SourceLastWriteTimeUtc, CacheLastWriteTimeUtc, ContentType, MaxAge, ContentLength); - var meta2 = new ImageCacheMetadata( + ImageCacheMetadata meta2 = new( meta.SourceLastWriteTimeUtc, meta.CacheLastWriteTimeUtc, meta.ContentType, @@ -52,7 +52,7 @@ public void EqualityChecksAreCorrect() Assert.Equal(meta, meta2); - var meta3 = new ImageCacheMetadata( + ImageCacheMetadata meta3 = new( SourceLastWriteTimeUtc, CacheLastWriteTimeUtc, "image/png", @@ -61,4 +61,25 @@ public void EqualityChecksAreCorrect() Assert.NotEqual(meta, meta3); } + + [Fact] + public async Task WriteAsyncRoundTripsViaReadAsync() + { + ImageCacheMetadata metadata = new( + SourceLastWriteTimeUtc, + CacheLastWriteTimeUtc, + ContentType, + MaxAge, + ContentLength); + + MemoryStream stream = new(); + await metadata.WriteAsync(stream); + + byte[] data = stream.ToArray(); + + await using MemoryStream readStream = new(data); + ImageCacheMetadata roundTrip = await ImageCacheMetadata.ReadAsync(readStream); + + Assert.Equal(metadata, roundTrip); + } } diff --git a/tests/ImageSharp.Web.Tests/Commands/CommandParserTests.cs b/tests/ImageSharp.Web.Tests/Commands/CommandParserTests.cs index a8b7ed70..29a293c3 100644 --- a/tests/ImageSharp.Web.Tests/Commands/CommandParserTests.cs +++ b/tests/ImageSharp.Web.Tests/Commands/CommandParserTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Web.Tests.Commands; public class CommandParserTests { private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; - private static readonly CultureInfo Dk = new CultureInfo("da-DK"); + private static readonly CultureInfo Dk = new("da-DK"); private const double Pi = 3.14159265358979; private static readonly string PiStringInv = Pi.ToString(CultureInfo.InvariantCulture); @@ -63,7 +63,7 @@ public class CommandParserTests { (long)RoundedPi, PiStringInv, Inv }, { (ulong)RoundedPi, PiStringInv, Inv }, { (float)Pi, PiStringInv, Inv }, - { (double)Pi, PiStringInv, Inv }, + { Pi, PiStringInv, Inv }, { (decimal)Pi, PiStringInv, Inv }, }; @@ -79,7 +79,7 @@ public class CommandParserTests { (long)RoundedPi, PiStringDk, Dk }, { (ulong)RoundedPi, PiStringDk, Dk }, { (float)Pi, PiStringDk, Dk }, - { (double)Pi, PiStringDk, Dk }, + { Pi, PiStringDk, Dk }, { (decimal)Pi, PiStringDk, Dk }, }; @@ -169,7 +169,7 @@ public void CommandParserCanConvert(T expected, string param, CultureInfo cul [Fact] public void CommandParseThrowsCorrectly() { - var emptyParser = new CommandParser(Array.Empty()); + CommandParser emptyParser = new(Array.Empty()); Assert.Throws( () => emptyParser.ParseValue("true", CultureInfo.InvariantCulture)); @@ -177,8 +177,8 @@ public void CommandParseThrowsCorrectly() private static CommandParser GetCommandParser() { - var converters = new List - { + List converters = + [ new IntegralNumberConverter(), new IntegralNumberConverter(), new IntegralNumberConverter(), @@ -224,7 +224,7 @@ private static CommandParser GetCommandParser() new ListConverter(), new ListConverter(), new ListConverter() - }; + ]; return new CommandParser(converters); } @@ -232,12 +232,14 @@ private static CommandParser GetCommandParser() private static string ToNumericList(CultureInfo culture, params T[] values) where T : IConvertible { - var sb = new StringBuilder(); - var ls = culture.TextInfo.ListSeparator[0]; + StringBuilder sb = new(); + char ls = culture.TextInfo.ListSeparator[0]; for (int i = 0; i < values.Length; i++) { +#pragma warning disable CA1305 // Specify IFormatProvider sb.AppendFormat(values[i].ToString(culture) + ls); +#pragma warning restore CA1305 // Specify IFormatProvider } return sb.ToString().TrimEnd(ls); diff --git a/tests/ImageSharp.Web.Tests/Commands/PresetOnlyQueryCollectionRequestParserTests.cs b/tests/ImageSharp.Web.Tests/Commands/PresetOnlyQueryCollectionRequestParserTests.cs index 39446044..a1f4f06f 100644 --- a/tests/ImageSharp.Web.Tests/Commands/PresetOnlyQueryCollectionRequestParserTests.cs +++ b/tests/ImageSharp.Web.Tests/Commands/PresetOnlyQueryCollectionRequestParserTests.cs @@ -85,9 +85,9 @@ public void PresetOnlyQueryCollectionRequestParserCommandsWithoutMatchingPreset( Assert.Equal(expected, actual); } - private static HttpContext CreateHttpContext(string query) + private static DefaultHttpContext CreateHttpContext(string query) { - var httpContext = new DefaultHttpContext(); + DefaultHttpContext httpContext = new(); httpContext.Request.Path = "/testwebsite.com/image-12345.jpeg"; httpContext.Request.QueryString = new QueryString(query); return httpContext; diff --git a/tests/ImageSharp.Web.Tests/Commands/QueryCollectionUriParserTests.cs b/tests/ImageSharp.Web.Tests/Commands/QueryCollectionUriParserTests.cs index 1b01577d..8a2a5d2d 100644 --- a/tests/ImageSharp.Web.Tests/Commands/QueryCollectionUriParserTests.cs +++ b/tests/ImageSharp.Web.Tests/Commands/QueryCollectionUriParserTests.cs @@ -23,9 +23,9 @@ public void QueryCollectionParserExtractsCommands() Assert.Equal(expected, actual); } - private static HttpContext CreateHttpContext() + private static DefaultHttpContext CreateHttpContext() { - var httpContext = new DefaultHttpContext(); + DefaultHttpContext httpContext = new(); httpContext.Request.Path = "/testwebsite.com/image-12345.jpeg"; // Duplicate height param to test replacements diff --git a/tests/ImageSharp.Web.Tests/DependencyInjection/MockCacheHash.cs b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeCacheHash.cs similarity index 86% rename from tests/ImageSharp.Web.Tests/DependencyInjection/MockCacheHash.cs rename to tests/ImageSharp.Web.Tests/DependencyInjection/FakeCacheHash.cs index 56657f77..0f820c44 100644 --- a/tests/ImageSharp.Web.Tests/DependencyInjection/MockCacheHash.cs +++ b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeCacheHash.cs @@ -5,7 +5,7 @@ namespace SixLabors.ImageSharp.Web.Tests.DependencyInjection; -public class MockCacheHash : ICacheHash +public class FakeCacheHash : ICacheHash { public string Create(string value, uint length) => null; } diff --git a/tests/ImageSharp.Web.Tests/DependencyInjection/MockCacheKey.cs b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeCacheKey.cs similarity index 90% rename from tests/ImageSharp.Web.Tests/DependencyInjection/MockCacheKey.cs rename to tests/ImageSharp.Web.Tests/DependencyInjection/FakeCacheKey.cs index 3a19b217..6280f271 100644 --- a/tests/ImageSharp.Web.Tests/DependencyInjection/MockCacheKey.cs +++ b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeCacheKey.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Web.Tests.DependencyInjection; -public class MockCacheKey : ICacheKey +public class FakeCacheKey : ICacheKey { public string Create(HttpContext context, CommandCollection commands) => null; } diff --git a/tests/ImageSharp.Web.Tests/DependencyInjection/MockCommandConverter.cs b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeCommandConverter.cs similarity index 78% rename from tests/ImageSharp.Web.Tests/DependencyInjection/MockCommandConverter.cs rename to tests/ImageSharp.Web.Tests/DependencyInjection/FakeCommandConverter.cs index 2bc47c0a..8283c8bd 100644 --- a/tests/ImageSharp.Web.Tests/DependencyInjection/MockCommandConverter.cs +++ b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeCommandConverter.cs @@ -7,9 +7,9 @@ namespace SixLabors.ImageSharp.Web.Tests.DependencyInjection; -public class MockCommandConverter : ICommandConverter +public class FakeCommandConverter : ICommandConverter { - public Type Type => typeof(MockCommandConverter); + public Type Type => typeof(FakeCommandConverter); public object ConvertFrom( CommandParser parser, diff --git a/tests/ImageSharp.Web.Tests/DependencyInjection/MockImageCache.cs b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeImageCache.cs similarity index 91% rename from tests/ImageSharp.Web.Tests/DependencyInjection/MockImageCache.cs rename to tests/ImageSharp.Web.Tests/DependencyInjection/FakeImageCache.cs index abfc656b..6e8e58a3 100644 --- a/tests/ImageSharp.Web.Tests/DependencyInjection/MockImageCache.cs +++ b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeImageCache.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Web.Tests.DependencyInjection; -public class MockImageCache : IImageCache +public class FakeImageCache : IImageCache { public Task GetAsync(string key) => Task.FromResult(null); diff --git a/tests/ImageSharp.Web.Tests/DependencyInjection/MockImageProvider.cs b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeImageProvider.cs similarity index 92% rename from tests/ImageSharp.Web.Tests/DependencyInjection/MockImageProvider.cs rename to tests/ImageSharp.Web.Tests/DependencyInjection/FakeImageProvider.cs index 602f10f5..eacd412e 100644 --- a/tests/ImageSharp.Web.Tests/DependencyInjection/MockImageProvider.cs +++ b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeImageProvider.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Web.Tests.DependencyInjection; -public class MockImageProvider : IImageProvider +public class FakeImageProvider : IImageProvider { public ProcessingBehavior ProcessingBehavior { get; set; } = ProcessingBehavior.All; diff --git a/tests/ImageSharp.Web.Tests/DependencyInjection/MockRequestParser.cs b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeRequestParser.cs similarity index 86% rename from tests/ImageSharp.Web.Tests/DependencyInjection/MockRequestParser.cs rename to tests/ImageSharp.Web.Tests/DependencyInjection/FakeRequestParser.cs index d9c2ad24..9cc128ea 100644 --- a/tests/ImageSharp.Web.Tests/DependencyInjection/MockRequestParser.cs +++ b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeRequestParser.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Web.Tests.DependencyInjection; -public class MockRequestParser : IRequestParser +public class FakeRequestParser : IRequestParser { public CommandCollection ParseRequestCommands(HttpContext context) => null; } diff --git a/tests/ImageSharp.Web.Tests/DependencyInjection/MockWebProcessor.cs b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeWebProcessor.cs similarity index 93% rename from tests/ImageSharp.Web.Tests/DependencyInjection/MockWebProcessor.cs rename to tests/ImageSharp.Web.Tests/DependencyInjection/FakeWebProcessor.cs index e2328def..a68432b6 100644 --- a/tests/ImageSharp.Web.Tests/DependencyInjection/MockWebProcessor.cs +++ b/tests/ImageSharp.Web.Tests/DependencyInjection/FakeWebProcessor.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Web.Tests.DependencyInjection; -public class MockWebProcessor : IImageWebProcessor +public class FakeWebProcessor : IImageWebProcessor { public IEnumerable Commands => Array.Empty(); diff --git a/tests/ImageSharp.Web.Tests/DependencyInjection/ServiceRegistrationExtensionsTests.cs b/tests/ImageSharp.Web.Tests/DependencyInjection/ServiceRegistrationExtensionsTests.cs index 4a22a158..7098c147 100644 --- a/tests/ImageSharp.Web.Tests/DependencyInjection/ServiceRegistrationExtensionsTests.cs +++ b/tests/ImageSharp.Web.Tests/DependencyInjection/ServiceRegistrationExtensionsTests.cs @@ -6,7 +6,6 @@ using SixLabors.ImageSharp.Web.Caching; using SixLabors.ImageSharp.Web.Commands; using SixLabors.ImageSharp.Web.Commands.Converters; -using SixLabors.ImageSharp.Web.DependencyInjection; using SixLabors.ImageSharp.Web.Processors; using SixLabors.ImageSharp.Web.Providers; @@ -39,12 +38,12 @@ private static bool IsServiceImplementationFactory(Se (descriptor.ImplementationFactory?.GetMethodInfo().ReturnType == typeof(TImplementation) || descriptor.ImplementationFactory?.Invoke(null)?.GetType() == typeof(TImplementation)); // OK to invoke the factory in tests - private static IReadOnlyList GetCollection(IServiceCollection serviceDescriptors) => serviceDescriptors.Where(x => x.ServiceType == typeof(T)).ToList(); + private static List GetCollection(IServiceCollection serviceDescriptors) => [.. serviceDescriptors.Where(x => x.ServiceType == typeof(T))]; [Fact] public void DefaultServicesAreRegistered() { - var services = new ServiceCollection(); + ServiceCollection services = new(); services.AddImageSharp(); Assert.Single(services, IsService); @@ -104,178 +103,178 @@ public void DefaultServicesAreRegistered() [Fact] public void CanSetRequestParser() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.SetRequestParser(); + builder.SetRequestParser(); Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + Assert.Single(services, IsServiceImplementationType); - builder.SetRequestParser(_ => new MockRequestParser()); + builder.SetRequestParser(_ => new FakeRequestParser()); Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + Assert.Single(services, IsServiceImplementationFactory); } [Fact] public void CanSetCache() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.SetCache(); + builder.SetCache(); Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + Assert.Single(services, IsServiceImplementationType); - builder.SetCache(_ => new MockImageCache()); + builder.SetCache(_ => new FakeImageCache()); Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + Assert.Single(services, IsServiceImplementationFactory); } [Fact] public void CanSetCacheKey() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.SetCacheKey(); + builder.SetCacheKey(); Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + Assert.Single(services, IsServiceImplementationType); - builder.SetCacheKey(_ => new MockCacheKey()); + builder.SetCacheKey(_ => new FakeCacheKey()); Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + Assert.Single(services, IsServiceImplementationFactory); } [Fact] public void CanSetCacheHash() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.SetCacheHash(); + builder.SetCacheHash(); Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + Assert.Single(services, IsServiceImplementationType); - builder.SetCacheHash(_ => new MockCacheHash()); + builder.SetCacheHash(_ => new FakeCacheHash()); Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + Assert.Single(services, IsServiceImplementationFactory); } [Fact] public void CanAddRemoveImageProviders() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddProvider(); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + builder.AddProvider(); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationType); - builder.RemoveProvider(); - Assert.DoesNotContain(services, IsService); + builder.RemoveProvider(); + Assert.DoesNotContain(services, IsService); } [Fact] public void CanInsertRemoveImageProviders() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.InsertProvider(0); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + builder.InsertProvider(0); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationType); - IReadOnlyList providers = GetCollection(services); + List providers = GetCollection(services); Assert.Equal(2, providers.Count); - Assert.True(IsService(providers[0])); - Assert.True(IsServiceImplementationType(providers[0])); + Assert.True(IsService(providers[0])); + Assert.True(IsServiceImplementationType(providers[0])); - builder.RemoveProvider(); - Assert.DoesNotContain(services, IsService); + builder.RemoveProvider(); + Assert.DoesNotContain(services, IsService); } [Fact] public void CanInsertIdempotentImageProviders() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.InsertProvider(0); - builder.InsertProvider(1); + builder.InsertProvider(0); + builder.InsertProvider(1); - Assert.Throws(() => builder.InsertProvider(2)); + Assert.Throws(() => builder.InsertProvider(2)); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationType); - IReadOnlyList providers = GetCollection(services); + List providers = GetCollection(services); Assert.Equal(2, providers.Count); - Assert.True(IsService(providers[1])); - Assert.True(IsServiceImplementationType(providers[1])); + Assert.True(IsService(providers[1])); + Assert.True(IsServiceImplementationType(providers[1])); } [Fact] public void CanAddRemoveFactoryImageProviders() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddProvider(_ => new MockImageProvider()); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + builder.AddProvider(_ => new FakeImageProvider()); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationFactory); - builder.RemoveProvider(); - Assert.DoesNotContain(services, IsService); + builder.RemoveProvider(); + Assert.DoesNotContain(services, IsService); } [Fact] public void CanInsertIdempotentFactoryImageProviders() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.InsertProvider(0, _ => new MockImageProvider()); - builder.InsertProvider(1, _ => new MockImageProvider()); + builder.InsertProvider(0, _ => new FakeImageProvider()); + builder.InsertProvider(1, _ => new FakeImageProvider()); - Assert.Throws(() => builder.InsertProvider(2, _ => new MockImageProvider())); + Assert.Throws(() => builder.InsertProvider(2, _ => new FakeImageProvider())); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationFactory); - IReadOnlyList providers = GetCollection(services); + List providers = GetCollection(services); Assert.Equal(2, providers.Count); - Assert.True(IsService(providers[1])); - Assert.True(IsServiceImplementationFactory(providers[1])); + Assert.True(IsService(providers[1])); + Assert.True(IsServiceImplementationFactory(providers[1])); } [Fact] public void CanInsertRemoveFactoryImageProviders() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.InsertProvider(0, _ => new MockImageProvider()); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + builder.InsertProvider(0, _ => new FakeImageProvider()); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationFactory); - IReadOnlyList providers = GetCollection(services); + List providers = GetCollection(services); Assert.Equal(2, providers.Count); - Assert.True(IsService(providers[0])); - Assert.True(IsServiceImplementationFactory(providers[0])); + Assert.True(IsService(providers[0])); + Assert.True(IsServiceImplementationFactory(providers[0])); - builder.RemoveProvider(); - Assert.DoesNotContain(services, IsService); + builder.RemoveProvider(); + Assert.DoesNotContain(services, IsService); } [Fact] public void CanAddRemoveAllImageProviders() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddProvider(); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + builder.AddProvider(); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationType); builder.ClearProviders(); Assert.DoesNotContain(services, IsService); @@ -284,12 +283,12 @@ public void CanAddRemoveAllImageProviders() [Fact] public void CanAddRemoveAllFactoryImageProviders() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddProvider(_ => new MockImageProvider()); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + builder.AddProvider(_ => new FakeImageProvider()); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationFactory); builder.ClearProviders(); Assert.DoesNotContain(services, IsService); @@ -298,40 +297,40 @@ public void CanAddRemoveAllFactoryImageProviders() [Fact] public void CanAddRemoveImageProcessors() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddProcessor(); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + builder.AddProcessor(); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationType); - builder.RemoveProcessor(); - Assert.DoesNotContain(services, IsService); + builder.RemoveProcessor(); + Assert.DoesNotContain(services, IsService); } [Fact] public void CanAddRemoveFactoryImageProcessors() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddProcessor(_ => new MockWebProcessor()); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + builder.AddProcessor(_ => new FakeWebProcessor()); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationFactory); - builder.RemoveProcessor(); - Assert.DoesNotContain(services, IsService); + builder.RemoveProcessor(); + Assert.DoesNotContain(services, IsService); } [Fact] public void CanAddRemoveAllImageProcessors() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddProcessor(); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + builder.AddProcessor(); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationType); builder.ClearProcessors(); Assert.DoesNotContain(services, IsService); @@ -340,12 +339,12 @@ public void CanAddRemoveAllImageProcessors() [Fact] public void CanAddRemoveAllFactoryImageProcessors() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddProcessor(_ => new MockWebProcessor()); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + builder.AddProcessor(_ => new FakeWebProcessor()); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationFactory); builder.ClearProcessors(); Assert.DoesNotContain(services, IsService); @@ -354,40 +353,40 @@ public void CanAddRemoveAllFactoryImageProcessors() [Fact] public void CanAddRemoveCommandConverters() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddConverter(); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + builder.AddConverter(); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationType); - builder.RemoveConverter(); - Assert.DoesNotContain(services, IsService); + builder.RemoveConverter(); + Assert.DoesNotContain(services, IsService); } [Fact] public void CanAddRemoveFactoryCommandConverters() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddConverter(_ => new MockCommandConverter()); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + builder.AddConverter(_ => new FakeCommandConverter()); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationFactory); - builder.RemoveConverter(); - Assert.DoesNotContain(services, IsService); + builder.RemoveConverter(); + Assert.DoesNotContain(services, IsService); } [Fact] public void CanAddRemoveAllCommandConverters() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddConverter(); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationType); + builder.AddConverter(); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationType); builder.ClearConverters(); Assert.DoesNotContain(services, IsService); @@ -396,12 +395,12 @@ public void CanAddRemoveAllCommandConverters() [Fact] public void CanAddRemoveAllFactoryCommandConverters() { - var services = new ServiceCollection(); + ServiceCollection services = new(); IImageSharpBuilder builder = services.AddImageSharp(); - builder.AddConverter(_ => new MockCommandConverter()); - Assert.Single(services, IsService); - Assert.Single(services, IsServiceImplementationFactory); + builder.AddConverter(_ => new FakeCommandConverter()); + Assert.Single(services, IsService); + Assert.Single(services, IsServiceImplementationFactory); builder.ClearConverters(); Assert.DoesNotContain(services, IsService); diff --git a/tests/ImageSharp.Web.Tests/Helpers/ExifOrientationUtilitiesTests.cs b/tests/ImageSharp.Web.Tests/Helpers/ExifOrientationUtilitiesTests.cs index 497c3029..fc7abb1f 100644 --- a/tests/ImageSharp.Web.Tests/Helpers/ExifOrientationUtilitiesTests.cs +++ b/tests/ImageSharp.Web.Tests/Helpers/ExifOrientationUtilitiesTests.cs @@ -23,7 +23,7 @@ public class ExifOrientationUtilitiesTests // │ │ F│ │ │ │ │ // │ │ │ │ │ │ │ // └─────┴─────┴─────┴─────┴─────┴─────┘ - public static TheoryData TransformVectorData = + public static TheoryData TransformVectorData { get; } = new() { { new Vector2(24F, 26F), Vector2.Zero, new Vector2(150, 100), ExifOrientationMode.Unknown, new Vector2(24F, 26F) }, @@ -47,7 +47,7 @@ public void CanTransformVector(Vector2 position, Vector2 min, Vector2 max, ushor Assert.Equal(expected.Y, actual.Y, 4); } - public static TheoryData TransformSizeData = + public static TheoryData TransformSizeData { get; } = new() { { new Size(150, 100), ExifOrientationMode.Unknown, new Size(150, 100) }, @@ -70,7 +70,7 @@ public void CanTransformSize(Size size, ushort orientation, Size expected) Assert.Equal(expected, actual); } - public static TheoryData TransformAnchorData = + public static TheoryData TransformAnchorData { get; } = new() { { AnchorPositionMode.Center, ExifOrientationMode.Unknown, AnchorPositionMode.Center }, diff --git a/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs b/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs index 104336db..d203b333 100644 --- a/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs +++ b/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Web.Tests.Helpers; public class FormatUtilitiesTests { - public static IEnumerable DefaultExtensions = + public static IEnumerable DefaultExtensions { get; } = Configuration.Default.ImageFormats.SelectMany(f => f.FileExtensions.Select(e => new object[] { e, e })); private static readonly FormatUtilities FormatUtilities = new(Options.Create(new ImageSharpMiddlewareOptions())); diff --git a/tests/ImageSharp.Web.Tests/ImageSharp.Web.Tests.csproj b/tests/ImageSharp.Web.Tests/ImageSharp.Web.Tests.csproj index 8ce5cb2e..1a972071 100644 --- a/tests/ImageSharp.Web.Tests/ImageSharp.Web.Tests.csproj +++ b/tests/ImageSharp.Web.Tests/ImageSharp.Web.Tests.csproj @@ -8,12 +8,12 @@ - net7.0;net6.0 + net8.0;net10.0 - net6.0 + net8.0 diff --git a/tests/ImageSharp.Web.Tests/Processors/AutoOrientWebProcessorTests.cs b/tests/ImageSharp.Web.Tests/Processors/AutoOrientWebProcessorTests.cs index 706c8f31..f1e1cf66 100644 --- a/tests/ImageSharp.Web.Tests/Processors/AutoOrientWebProcessorTests.cs +++ b/tests/ImageSharp.Web.Tests/Processors/AutoOrientWebProcessorTests.cs @@ -24,7 +24,6 @@ public void AutoOrientWebProcessor_UpdatesOrientation() { new(AutoOrientWebProcessor.AutoOrient, bool.TrueString) } }; - const ushort tl = 1; const ushort br = 3; using Image image = new(1, 1); image.Metadata.ExifProfile = new(); @@ -36,7 +35,7 @@ public void AutoOrientWebProcessor_UpdatesOrientation() using FormattedImage formatted = new(image, PngFormat.Instance); new AutoOrientWebProcessor().Process(formatted, null, commands, parser, culture); - Assert.True(image.Metadata.ExifProfile.TryGetValue(ExifTag.Orientation, out orientation)); - Assert.Equal(tl, orientation.Value); + // Orientation will be removed from the image metadata after processing. + Assert.False(image.Metadata.ExifProfile.TryGetValue(ExifTag.Orientation, out orientation)); } } diff --git a/tests/ImageSharp.Web.Tests/Processors/BackgroundColorWebProcessorTests.cs b/tests/ImageSharp.Web.Tests/Processors/BackgroundColorWebProcessorTests.cs index 6ad05672..bc64d821 100644 --- a/tests/ImageSharp.Web.Tests/Processors/BackgroundColorWebProcessorTests.cs +++ b/tests/ImageSharp.Web.Tests/Processors/BackgroundColorWebProcessorTests.cs @@ -23,13 +23,14 @@ public void BackgroundColorWebProcessor_UpdatesColor() { new(BackgroundColorWebProcessor.Color, nameof(Color.Orange)) } }; - using var image = new Image(1, 1); - Assert.True(Color.Transparent.Equals(image[0, 0])); + using Image image = new(1, 1); - using var formatted = new FormattedImage(image, PngFormat.Instance); + Assert.Equal(Color.Transparent.ToPixel(), image[0, 0]); + + using FormattedImage formatted = new(image, PngFormat.Instance); new BackgroundColorWebProcessor().Process(formatted, null, commands, parser, culture); - Assert.True(Color.Orange.Equals(image[0, 0])); + Assert.Equal(Color.Orange.ToPixel(), image[0, 0]); } [Theory] diff --git a/tests/ImageSharp.Web.Tests/Processors/FormattedImageTests.cs b/tests/ImageSharp.Web.Tests/Processors/FormattedImageTests.cs index 982fb5ea..fc93425d 100644 --- a/tests/ImageSharp.Web.Tests/Processors/FormattedImageTests.cs +++ b/tests/ImageSharp.Web.Tests/Processors/FormattedImageTests.cs @@ -56,14 +56,14 @@ public void CanSetEncoder() formatted.Format = JpegFormat.Instance; Assert.Equal(typeof(JpegEncoder), formatted.Encoder.GetType()); - JpegEncodingColor current = ((JpegEncoder)formatted.Encoder).ColorType.GetValueOrDefault(); + JpegColorType current = ((JpegEncoder)formatted.Encoder).ColorType.GetValueOrDefault(); - Assert.Equal(JpegEncodingColor.YCbCrRatio420, current); - formatted.Encoder = new JpegEncoder { ColorType = JpegEncodingColor.YCbCrRatio444 }; + Assert.Equal(JpegColorType.YCbCrRatio420, current); + formatted.Encoder = new JpegEncoder { ColorType = JpegColorType.YCbCrRatio444 }; - JpegEncodingColor replacement = ((JpegEncoder)formatted.Encoder).ColorType.GetValueOrDefault(); + JpegColorType replacement = ((JpegEncoder)formatted.Encoder).ColorType.GetValueOrDefault(); Assert.NotEqual(current, replacement); - Assert.Equal(JpegEncodingColor.YCbCrRatio444, replacement); + Assert.Equal(JpegColorType.YCbCrRatio444, replacement); } } diff --git a/tests/ImageSharp.Web.Tests/Processors/QualityWebProcessorTests.cs b/tests/ImageSharp.Web.Tests/Processors/QualityWebProcessorTests.cs index d4bae8c1..159f50d5 100644 --- a/tests/ImageSharp.Web.Tests/Processors/QualityWebProcessorTests.cs +++ b/tests/ImageSharp.Web.Tests/Processors/QualityWebProcessorTests.cs @@ -26,8 +26,8 @@ public void QualityWebProcessor_UpdatesJpegQuality() { new(QualityWebProcessor.Quality, "42") }, }; - using var image = new Image(1, 1); - using var formatted = new FormattedImage(image, JpegFormat.Instance); + using Image image = new(1, 1); + using FormattedImage formatted = new(image, JpegFormat.Instance); Assert.Equal(JpegFormat.Instance, formatted.Format); Assert.Equal(typeof(JpegEncoder), formatted.Encoder.GetType()); @@ -51,8 +51,8 @@ public void QualityWebProcessor_UpdatesWebpQuality() }, }; - using var image = new Image(1, 1); - using var formatted = new FormattedImage(image, WebpFormat.Instance); + using Image image = new(1, 1); + using FormattedImage formatted = new(image, WebpFormat.Instance); Assert.Equal(WebpFormat.Instance, formatted.Format); Assert.Equal(typeof(WebpEncoder), formatted.Encoder.GetType()); @@ -67,17 +67,17 @@ public void QualityWebProcessor_UpdatesWebpQuality() [Fact] public void QualityWebProcessor_CanReportAlphaRequirements() { - var converters = new List - { + List converters = + [ new IntegralNumberConverter(), - }; + ]; - var parser = new CommandParser(converters); + CommandParser parser = new(converters); CultureInfo culture = CultureInfo.InvariantCulture; CommandCollection commands = new() { - { new(QualityWebProcessor.Quality, this.random.Next(1, 100).ToString()) }, + { new(QualityWebProcessor.Quality, this.random.Next(1, 100).ToString(CultureInfo.InvariantCulture)) }, }; Assert.False(new QualityWebProcessor().RequiresTrueColorPixelFormat(commands, parser, culture)); diff --git a/tests/ImageSharp.Web.Tests/Processors/ResizeWebProcessorTests.cs b/tests/ImageSharp.Web.Tests/Processors/ResizeWebProcessorTests.cs index 62ae8d28..092c8715 100644 --- a/tests/ImageSharp.Web.Tests/Processors/ResizeWebProcessorTests.cs +++ b/tests/ImageSharp.Web.Tests/Processors/ResizeWebProcessorTests.cs @@ -36,17 +36,17 @@ public void ResizeWebProcessor_UpdatesSize(string resampler) const int width = 4; const int height = 6; - var converters = new List - { + List converters = + [ new IntegralNumberConverter(), new ArrayConverter(), new EnumConverter(), new SimpleCommandConverter(), new SimpleCommandConverter(), new ColorConverter() - }; + ]; - var parser = new CommandParser(converters); + CommandParser parser = new(converters); CultureInfo culture = CultureInfo.InvariantCulture; CommandCollection commands = new() @@ -54,14 +54,14 @@ public void ResizeWebProcessor_UpdatesSize(string resampler) // We only need to do this for the unit tests. // Commands generated via URL will automatically be converted to lowecase { new(ResizeWebProcessor.Sampler, resampler.ToLowerInvariant()) }, - { new(ResizeWebProcessor.Width, width.ToString()) }, - { new(ResizeWebProcessor.Height, height.ToString()) }, + { new(ResizeWebProcessor.Width, width.ToString(CultureInfo.InvariantCulture)) }, + { new(ResizeWebProcessor.Height, height.ToString(CultureInfo.InvariantCulture)) }, { new(ResizeWebProcessor.Xy, "0,0") }, { new(ResizeWebProcessor.Mode, nameof(ResizeMode.Stretch)) } }; - using var image = new Image(1, 1); - using var formatted = new FormattedImage(image, PngFormat.Instance); + using Image image = new(1, 1); + using FormattedImage formatted = new(image, PngFormat.Instance); new ResizeWebProcessor().Process(formatted, null, commands, parser, culture); Assert.Equal(width, image.Width); @@ -83,31 +83,31 @@ public void ResizeWebProcessor_RespectsOrientation_Size(ushort orientation, bool const int width = 4; const int height = 6; - var converters = new List - { + List converters = + [ new IntegralNumberConverter(), new ArrayConverter(), new EnumConverter(), new SimpleCommandConverter(), new SimpleCommandConverter(), new ColorConverter() - }; + ]; - var parser = new CommandParser(converters); + CommandParser parser = new(converters); CultureInfo culture = CultureInfo.InvariantCulture; CommandCollection commands = new() { - { new(ResizeWebProcessor.Width, width.ToString()) }, - { new(ResizeWebProcessor.Height, height.ToString()) }, + { new(ResizeWebProcessor.Width, width.ToString(CultureInfo.InvariantCulture)) }, + { new(ResizeWebProcessor.Height, height.ToString(CultureInfo.InvariantCulture)) }, { new(ResizeWebProcessor.Mode, nameof(ResizeMode.Stretch)) } }; - using var image = new Image(1, 1); + using Image image = new(1, 1); image.Metadata.ExifProfile = new(); image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, orientation); - using var formatted = new FormattedImage(image, PngFormat.Instance); + using FormattedImage formatted = new(image, PngFormat.Instance); new ResizeWebProcessor().Process(formatted, null, commands, parser, culture); if (rotated) @@ -139,31 +139,31 @@ public void ResizeWebProcessor_RespectsOrientation_Center(ushort orientation) const float x = .25F; const float y = .5F; - var converters = new List - { + List converters = + [ new IntegralNumberConverter(), new ArrayConverter(), new EnumConverter(), new SimpleCommandConverter(), new SimpleCommandConverter(), new ColorConverter() - }; + ]; - var parser = new CommandParser(converters); + CommandParser parser = new(converters); CultureInfo culture = CultureInfo.InvariantCulture; CommandCollection commands = new() { - { new(ResizeWebProcessor.Width, width.ToString()) }, - { new(ResizeWebProcessor.Height, height.ToString()) }, + { new(ResizeWebProcessor.Width, width.ToString(CultureInfo.InvariantCulture)) }, + { new(ResizeWebProcessor.Height, height.ToString(CultureInfo.InvariantCulture)) }, { new(ResizeWebProcessor.Xy, FormattableString.Invariant($"{x},{y}")) }, { new(ResizeWebProcessor.Mode, nameof(ResizeMode.Stretch)) } }; - using var image = new Image(3, 3); + using Image image = new(3, 3); image.Metadata.ExifProfile = new(); image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, orientation); - using var formatted = new FormattedImage(image, PngFormat.Instance); + using FormattedImage formatted = new(image, PngFormat.Instance); PointF expected = ExifOrientationUtilities.Transform(new Vector2(x, y), Vector2.Zero, Vector2.One, orientation); ResizeOptions options = ResizeWebProcessor.GetResizeOptions(formatted, commands, parser, culture); @@ -182,17 +182,17 @@ public void ResizeWebProcessor_RespectsOrientation_Center(ushort orientation) [InlineData(ExifOrientationMode.LeftBottom)] public void ResizeWebProcessor_RespectsOrientation_Anchor(ushort orientation) { - var converters = new List - { + List converters = + [ new IntegralNumberConverter(), new ArrayConverter(), new EnumConverter(), new SimpleCommandConverter(), new SimpleCommandConverter(), new ColorConverter() - }; + ]; - var parser = new CommandParser(converters); + CommandParser parser = new(converters); CultureInfo culture = CultureInfo.InvariantCulture; using Image image = new(1, 1); @@ -204,8 +204,8 @@ public void ResizeWebProcessor_RespectsOrientation_Anchor(ushort orientation) { CommandCollection commands = new() { - { new(ResizeWebProcessor.Width, 4.ToString()) }, - { new(ResizeWebProcessor.Height, 6.ToString()) }, + { new(ResizeWebProcessor.Width, 4.ToString(CultureInfo.InvariantCulture)) }, + { new(ResizeWebProcessor.Height, 6.ToString(CultureInfo.InvariantCulture)) }, { new(ResizeWebProcessor.Mode, nameof(ResizeMode.Stretch)) }, { new(ResizeWebProcessor.Anchor, anchor.ToString()) }, }; @@ -231,32 +231,32 @@ public void ResizeWebProcessor_CanIgnoreOrientation(ushort orientation) const int width = 4; const int height = 6; - var converters = new List - { + List converters = + [ new IntegralNumberConverter(), new ArrayConverter(), new EnumConverter(), new SimpleCommandConverter(), new SimpleCommandConverter(), new ColorConverter() - }; + ]; - var parser = new CommandParser(converters); + CommandParser parser = new(converters); CultureInfo culture = CultureInfo.InvariantCulture; CommandCollection commands = new() { - { new(ResizeWebProcessor.Width, width.ToString()) }, - { new(ResizeWebProcessor.Height, height.ToString()) }, + { new(ResizeWebProcessor.Width, width.ToString(CultureInfo.InvariantCulture)) }, + { new(ResizeWebProcessor.Height, height.ToString(CultureInfo.InvariantCulture)) }, { new(ResizeWebProcessor.Mode, nameof(ResizeMode.Stretch)) }, { new(ResizeWebProcessor.Orient, bool.FalseString) } }; - using var image = new Image(1, 1); + using Image image = new(1, 1); image.Metadata.ExifProfile = new(); image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, orientation); - using var formatted = new FormattedImage(image, PngFormat.Instance); + using FormattedImage formatted = new(image, PngFormat.Instance); new ResizeWebProcessor().Process(formatted, null, commands, parser, culture); Assert.Equal(width, image.Width); @@ -273,12 +273,12 @@ public void ResizeWebProcessor_CanIgnoreOrientation(ushort orientation) [InlineData(ResizeMode.Manual, false)] public void ResizeWebProcessor_CanReportAlphaRequirements(ResizeMode resizeMode, bool requiresAlpha) { - var converters = new List - { + List converters = + [ new EnumConverter(), - }; + ]; - var parser = new CommandParser(converters); + CommandParser parser = new(converters); CultureInfo culture = CultureInfo.InvariantCulture; CommandCollection commands = new() diff --git a/tests/ImageSharp.Web.Tests/Processors/WebProcessingExtensionsTests.cs b/tests/ImageSharp.Web.Tests/Processors/WebProcessingExtensionsTests.cs index e31027c2..969fb0a3 100644 --- a/tests/ImageSharp.Web.Tests/Processors/WebProcessingExtensionsTests.cs +++ b/tests/ImageSharp.Web.Tests/Processors/WebProcessingExtensionsTests.cs @@ -17,7 +17,7 @@ public void WebProcessingExtensions_GetBySupportedCommands() new QualityWebProcessor(), new ResizeWebProcessor(), new BackgroundColorWebProcessor(), - new MockWebProcessor() + new FakeWebProcessor() }; CommandCollection commands = new() @@ -39,7 +39,7 @@ public void WebProcessingExtensions_GetBySupportedCommands_Empty() { var processors = new IImageWebProcessor[] { - new MockWebProcessor() + new FakeWebProcessor() }; CommandCollection commands = new(); diff --git a/tests/ImageSharp.Web.Tests/TagHelpers/HmacTokenTagHelperTests.cs b/tests/ImageSharp.Web.Tests/TagHelpers/HmacTokenTagHelperTests.cs index 62f15d53..ad37b845 100644 --- a/tests/ImageSharp.Web.Tests/TagHelpers/HmacTokenTagHelperTests.cs +++ b/tests/ImageSharp.Web.Tests/TagHelpers/HmacTokenTagHelperTests.cs @@ -20,7 +20,6 @@ using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using Microsoft.Extensions.WebEncoders.Testing; -using SixLabors.ImageSharp.Web.DependencyInjection; using SixLabors.ImageSharp.Web.Middleware; using SixLabors.ImageSharp.Web.TagHelpers; @@ -32,7 +31,7 @@ public HmacTokenTagHelperTests() { ServiceCollection services = new(); services.AddSingleton(); - services.AddImageSharp(options => options.HMACSecretKey = new byte[] { 1, 2, 3, 4, 5 }); + services.AddImageSharp(options => options.HMACSecretKey = [1, 2, 3, 4, 5]); this.Provider = services.BuildServiceProvider(); } @@ -108,14 +107,14 @@ private static TagHelperContext MakeTagHelperContext( private static TagHelperOutput MakeImageTagHelperOutput(TagHelperAttributeList attributes) { - attributes ??= new TagHelperAttributeList(); + attributes ??= []; return new TagHelperOutput( "img", attributes, getChildContentAsync: (useCachedResult, encoder) => { - var tagHelperContent = new DefaultTagHelperContent(); + DefaultTagHelperContent tagHelperContent = new(); tagHelperContent.SetContent(default); return Task.FromResult(tagHelperContent); }); @@ -123,14 +122,14 @@ private static TagHelperOutput MakeImageTagHelperOutput(TagHelperAttributeList a private static ViewContext MakeViewContext(string requestPathBase = null) { - var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); + ActionContext actionContext = new(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); if (requestPathBase != null) { actionContext.HttpContext.Request.PathBase = new PathString(requestPathBase); } - var metadataProvider = new EmptyModelMetadataProvider(); - var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary()); + EmptyModelMetadataProvider metadataProvider = new(); + ViewDataDictionary viewData = new(metadataProvider, new ModelStateDictionary()); return new ViewContext( actionContext, new FakeView(), @@ -142,14 +141,14 @@ private static ViewContext MakeViewContext(string requestPathBase = null) public void Dispose() => this.Provider.Dispose(); - private class FakeView : IView + private sealed class FakeView : IView { public string Path { get; } public Task RenderAsync(ViewContext context) => throw new NotSupportedException(); } - private class FakeTempDataDictionary : Dictionary, ITempDataDictionary + private sealed class FakeTempDataDictionary : Dictionary, ITempDataDictionary { public void Keep() => throw new NotSupportedException(); @@ -162,7 +161,7 @@ private class FakeTempDataDictionary : Dictionary, ITempDataDict public void Save() => throw new NotSupportedException(); } - private class FakeWebHostEnvironment : IWebHostEnvironment + private sealed class FakeWebHostEnvironment : IWebHostEnvironment { public string WebRootPath { get; set; } @@ -177,7 +176,7 @@ private class FakeWebHostEnvironment : IWebHostEnvironment public string EnvironmentName { get; set; } } - private class FakeFileProvider : IFileProvider + private sealed class FakeFileProvider : IFileProvider { public IDirectoryContents GetDirectoryContents(string subpath) => new FakeDirectoryContents(); @@ -186,7 +185,7 @@ private class FakeFileProvider : IFileProvider public IChangeToken Watch(string filter) => new FakeFileChangeToken(); } - private class FakeFileChangeToken : IChangeToken + private sealed class FakeFileChangeToken : IChangeToken { public FakeFileChangeToken(string filter = "") => this.Filter = filter; @@ -208,7 +207,7 @@ public void Dispose() public override string ToString() => this.Filter; } - private class FakeDirectoryContents : IDirectoryContents + private sealed class FakeDirectoryContents : IDirectoryContents { public bool Exists { get; } @@ -217,7 +216,7 @@ private class FakeDirectoryContents : IDirectoryContents IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); } - private class FakeFileInfo : IFileInfo + private sealed class FakeFileInfo : IFileInfo { public bool Exists { get; } = true; @@ -234,12 +233,12 @@ private class FakeFileInfo : IFileInfo public Stream CreateReadStream() => new MemoryStream(Encoding.UTF8.GetBytes("Hello World!")); } - private class FakeUrlHelperFactory : IUrlHelperFactory + private sealed class FakeUrlHelperFactory : IUrlHelperFactory { public IUrlHelper GetUrlHelper(ActionContext context) => new FakeUrlHelper() { ActionContext = context }; } - private class FakeUrlHelper : IUrlHelper + private sealed class FakeUrlHelper : IUrlHelper { public ActionContext ActionContext { get; set; } @@ -247,7 +246,7 @@ private class FakeUrlHelper : IUrlHelper // Ensure expanded path does not look like an absolute path on Linux, avoiding // https://github.com/aspnet/External/issues/21 - [return: NotNullIfNotNull("contentPath")] + [return: NotNullIfNotNull(nameof(contentPath))] public string Content(string contentPath) => contentPath.Replace("~/", "virtualRoot/"); public bool IsLocalUrl([NotNullWhen(true)] string url) => throw new NotSupportedException(); diff --git a/tests/ImageSharp.Web.Tests/TagHelpers/ImageTagHelperTests.cs b/tests/ImageSharp.Web.Tests/TagHelpers/ImageTagHelperTests.cs index 9f8acd02..8eca2bff 100644 --- a/tests/ImageSharp.Web.Tests/TagHelpers/ImageTagHelperTests.cs +++ b/tests/ImageSharp.Web.Tests/TagHelpers/ImageTagHelperTests.cs @@ -22,7 +22,6 @@ using Microsoft.Extensions.Primitives; using Microsoft.Extensions.WebEncoders.Testing; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Web.DependencyInjection; using SixLabors.ImageSharp.Web.Middleware; using SixLabors.ImageSharp.Web.Processors; using SixLabors.ImageSharp.Web.TagHelpers; @@ -52,12 +51,16 @@ public void Process_SrcDefaultsToTagHelperOutputSrcAttributeAddedByOtherTagHelpe string expectedSrcPrefix) { // Arrange +#pragma warning disable IDE0028 // Simplify collection initialization +#pragma warning disable IDE0306 // Simplify collection initialization TagHelperAttributeList allAttributes = new( new TagHelperAttributeList { { "alt", new HtmlString("Testing") }, { "width", 100 }, }); +#pragma warning restore IDE0306 // Simplify collection initialization +#pragma warning restore IDE0028 // Simplify collection initialization TagHelperContext context = MakeTagHelperContext(allAttributes); TagHelperAttributeList outputAttributes = new() @@ -727,7 +730,7 @@ private static TagHelperContext MakeTagHelperContext( private static TagHelperOutput MakeImageTagHelperOutput(TagHelperAttributeList attributes) { - attributes ??= new TagHelperAttributeList(); + attributes ??= []; return new TagHelperOutput( "img", @@ -761,14 +764,14 @@ private static ViewContext MakeViewContext(string requestPathBase = null) public void Dispose() => this.Provider.Dispose(); - private class FakeView : IView + private sealed class FakeView : IView { public string Path { get; } public Task RenderAsync(ViewContext context) => throw new NotSupportedException(); } - private class FakeTempDataDictionary : Dictionary, ITempDataDictionary + private sealed class FakeTempDataDictionary : Dictionary, ITempDataDictionary { public void Keep() => throw new NotSupportedException(); @@ -781,7 +784,7 @@ private class FakeTempDataDictionary : Dictionary, ITempDataDict public void Save() => throw new NotSupportedException(); } - private class FakeWebHostEnvironment : IWebHostEnvironment + private sealed class FakeWebHostEnvironment : IWebHostEnvironment { public string WebRootPath { get; set; } @@ -796,7 +799,7 @@ private class FakeWebHostEnvironment : IWebHostEnvironment public string EnvironmentName { get; set; } } - private class FakeFileProvider : IFileProvider + private sealed class FakeFileProvider : IFileProvider { public IDirectoryContents GetDirectoryContents(string subpath) => new FakeDirectoryContents(); @@ -805,7 +808,7 @@ private class FakeFileProvider : IFileProvider public IChangeToken Watch(string filter) => new FakeFileChangeToken(); } - private class FakeFileChangeToken : IChangeToken + private sealed class FakeFileChangeToken : IChangeToken { public FakeFileChangeToken(string filter = "") => this.Filter = filter; @@ -827,7 +830,7 @@ public void Dispose() public override string ToString() => this.Filter; } - private class FakeDirectoryContents : IDirectoryContents + private sealed class FakeDirectoryContents : IDirectoryContents { public bool Exists { get; } @@ -836,7 +839,7 @@ private class FakeDirectoryContents : IDirectoryContents IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); } - private class FakeFileInfo : IFileInfo + private sealed class FakeFileInfo : IFileInfo { public bool Exists { get; } = true; @@ -853,12 +856,12 @@ private class FakeFileInfo : IFileInfo public Stream CreateReadStream() => new MemoryStream(Encoding.UTF8.GetBytes("Hello World!")); } - private class FakeUrlHelperFactory : IUrlHelperFactory + private sealed class FakeUrlHelperFactory : IUrlHelperFactory { public IUrlHelper GetUrlHelper(ActionContext context) => new FakeUrlHelper() { ActionContext = context }; } - private class FakeUrlHelper : IUrlHelper + private sealed class FakeUrlHelper : IUrlHelper { public ActionContext ActionContext { get; set; } @@ -866,7 +869,7 @@ private class FakeUrlHelper : IUrlHelper // Ensure expanded path does not look like an absolute path on Linux, avoiding // https://github.com/aspnet/External/issues/21 - [return: NotNullIfNotNull("contentPath")] + [return: NotNullIfNotNull(nameof(contentPath))] public string Content(string contentPath) => contentPath.Replace("~/", "virtualRoot/"); public bool IsLocalUrl([NotNullWhen(true)] string url) => throw new NotSupportedException(); diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageCacheCacheFolderTestServerFixture.cs b/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageCacheCacheFolderTestServerFixture.cs index d452ef6b..2445d4c3 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageCacheCacheFolderTestServerFixture.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageCacheCacheFolderTestServerFixture.cs @@ -3,9 +3,8 @@ using Amazon.S3; using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Web.Caching.AWS; -using SixLabors.ImageSharp.Web.DependencyInjection; -using SixLabors.ImageSharp.Web.Providers.AWS; +using SixLabors.ImageSharp.Web.AWS.Caching; +using SixLabors.ImageSharp.Web.AWS.Providers; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageCacheTestServerFixture.cs b/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageCacheTestServerFixture.cs index cb016f22..cb25191b 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageCacheTestServerFixture.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageCacheTestServerFixture.cs @@ -3,9 +3,8 @@ using Amazon.S3; using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Web.Caching.AWS; -using SixLabors.ImageSharp.Web.DependencyInjection; -using SixLabors.ImageSharp.Web.Providers.AWS; +using SixLabors.ImageSharp.Web.AWS.Caching; +using SixLabors.ImageSharp.Web.AWS.Providers; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageImageProviderFactory.cs b/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageImageProviderFactory.cs index 58ef0d87..38d8b2b2 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageImageProviderFactory.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageImageProviderFactory.cs @@ -8,7 +8,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Options; -using SixLabors.ImageSharp.Web.Providers.AWS; +using SixLabors.ImageSharp.Web.AWS; +using SixLabors.ImageSharp.Web.AWS.Providers; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/AuthenticatedTestServerFixture.cs b/tests/ImageSharp.Web.Tests/TestUtilities/AuthenticatedTestServerFixture.cs index 26954d90..34c57775 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/AuthenticatedTestServerFixture.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/AuthenticatedTestServerFixture.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Web.DependencyInjection; using SixLabors.ImageSharp.Web.Middleware; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageCacheCacheFolderTestServerFixture.cs b/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageCacheCacheFolderTestServerFixture.cs index 9b678c66..3e2f6843 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageCacheCacheFolderTestServerFixture.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageCacheCacheFolderTestServerFixture.cs @@ -3,9 +3,8 @@ using Azure.Storage.Blobs.Models; using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Web.Caching.Azure; -using SixLabors.ImageSharp.Web.DependencyInjection; -using SixLabors.ImageSharp.Web.Providers.Azure; +using SixLabors.ImageSharp.Web.Azure.Caching; +using SixLabors.ImageSharp.Web.Azure.Providers; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageCacheTestServerFixture.cs b/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageCacheTestServerFixture.cs index e2002a9a..7142c45b 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageCacheTestServerFixture.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageCacheTestServerFixture.cs @@ -3,9 +3,8 @@ using Azure.Storage.Blobs.Models; using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Web.Caching.Azure; -using SixLabors.ImageSharp.Web.DependencyInjection; -using SixLabors.ImageSharp.Web.Providers.Azure; +using SixLabors.ImageSharp.Web.Azure.Caching; +using SixLabors.ImageSharp.Web.Azure.Providers; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageImageProviderFactory.cs b/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageImageProviderFactory.cs index 95836089..0f13167d 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageImageProviderFactory.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/AzureBlobStorageImageProviderFactory.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Options; -using SixLabors.ImageSharp.Web.Providers.Azure; +using SixLabors.ImageSharp.Web.Azure.Providers; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; @@ -27,7 +27,7 @@ private static void InitializeAzureStorage(IServiceProvider services, AzureBlobS { // Upload an image to the Azure Test Storage; AzureBlobContainerClientOptions containerOptions = options.BlobContainers.First(); - var container = new BlobContainerClient(containerOptions.ConnectionString, containerOptions.ContainerName); + BlobContainerClient container = new(containerOptions.ConnectionString, containerOptions.ContainerName); container.CreateIfNotExists(PublicAccessType.Blob); IWebHostEnvironment environment = services.GetRequiredService(); @@ -40,14 +40,14 @@ private static void InitializeAzureStorage(IServiceProvider services, AzureBlobS using Stream stream = file.CreateReadStream(); // Set the max-age property so we get coverage for testing is in our Azure provider. - var cacheControl = new CacheControlHeaderValue + CacheControlHeaderValue cacheControl = new() { Public = true, MaxAge = TimeSpan.FromDays(7), MustRevalidate = true }; - var headers = new BlobHttpHeaders + BlobHttpHeaders headers = new() { CacheControl = cacheControl.ToString(), }; diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/PhysicalFileSystemCacheAuthenticatedTestServerFixture.cs b/tests/ImageSharp.Web.Tests/TestUtilities/PhysicalFileSystemCacheAuthenticatedTestServerFixture.cs index 0991f610..33ee831b 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/PhysicalFileSystemCacheAuthenticatedTestServerFixture.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/PhysicalFileSystemCacheAuthenticatedTestServerFixture.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using SixLabors.ImageSharp.Web.Caching; -using SixLabors.ImageSharp.Web.DependencyInjection; using SixLabors.ImageSharp.Web.Providers; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/PhysicalFileSystemCacheTestServerFixture.cs b/tests/ImageSharp.Web.Tests/TestUtilities/PhysicalFileSystemCacheTestServerFixture.cs index d9a7af71..c3228e00 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/PhysicalFileSystemCacheTestServerFixture.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/PhysicalFileSystemCacheTestServerFixture.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using SixLabors.ImageSharp.Web.Caching; -using SixLabors.ImageSharp.Web.DependencyInjection; using SixLabors.ImageSharp.Web.Providers; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Web.Tests/TestUtilities/TestEnvironment.cs index 33a6c62a..85de0375 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/TestEnvironment.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/TestEnvironment.cs @@ -22,7 +22,8 @@ internal static bool RunsOnCI // try reading the environment directly. // https://docs.github.com/en/actions/learn-github-actions/environment-variables string variable = Environment.GetEnvironmentVariable("CI"); - bool.TryParse(variable, out bool result); + + _ = bool.TryParse(variable, out bool result); return result; } } diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/TestServerFixture.cs b/tests/ImageSharp.Web.Tests/TestUtilities/TestServerFixture.cs index bab86ef6..10d01618 100644 --- a/tests/ImageSharp.Web.Tests/TestUtilities/TestServerFixture.cs +++ b/tests/ImageSharp.Web.Tests/TestUtilities/TestServerFixture.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Web.DependencyInjection; +using SixLabors.ImageSharp.Web; using SixLabors.ImageSharp.Web.Middleware; namespace SixLabors.ImageSharp.Web.Tests.TestUtilities; @@ -68,7 +68,7 @@ protected void ConfigureServices(IServiceCollection services) return onParseCommandsAsync.Invoke(context); }; - Func> onBeforeLoadAsync = options.OnBeforeLoadAsync; + Func> onBeforeLoadAsync = options.OnBeforeLoadAsync; options.OnBeforeLoadAsync = (context, configuration) => {