diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index c0933e1c6..587be4254 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -50,6 +50,7 @@ jobs: strong-name-key-filename: cuemon.snk runs-on: ${{ matrix.arch == 'ARM64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} upload-build-artifact-name: build-${{ matrix.configuration }}-${{ matrix.arch }} + include-preview: true secrets: GCP_TOKEN: ${{ secrets.GCP_TOKEN }} GCP_BUCKETNAME: ${{ secrets.GCP_BUCKETNAME }} @@ -65,7 +66,7 @@ jobs: configuration: ${{ matrix.configuration }} version: ${{ needs.build.outputs.version }} download-build-artifact-pattern: build-${{ matrix.configuration }}-X64 - + include-preview: true test_linux: name: call-test-linux @@ -84,6 +85,7 @@ jobs: build: true # we need to build due to xUnitv3 restore: true # we need to restore since we disabled caching download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }} + include-preview: true test_windows: name: call-test-windows @@ -103,6 +105,7 @@ jobs: build: true # we need to build for .net48 restore: true # apparently we need to restore for .net48 download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }} + include-preview: true integration_test: name: ⚗️ Integration Test @@ -120,6 +123,8 @@ jobs: - name: Install .NET uses: codebeltnet/install-dotnet@v3 + with: + includePreview: true - name: Install .NET Tool - Report Generator uses: codebeltnet/dotnet-tool-install-reportgenerator@v1 @@ -251,6 +256,7 @@ jobs: organization: geekle projectKey: Cuemon version: ${{ needs.build.outputs.version }} + include-preview: true secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/AGENTS.md b/AGENTS.md index 1f1598f73..017d297ae 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,12 +15,12 @@ Follow the repo rules first; do not invent commands or conventions. ## Toolchain - .NET SDK with `LangVersion=latest`. -- Source TFMs: `net10.0;net9.0;netstandard2.0`. -- Test TFMs: `net10.0;net9.0` on Linux; adds `net48` on Windows. -- Benchmark TFMs: `net10.0;net9.0`. +- Source TFMs: `net11.0;net10.0;netstandard2.0`. +- Test TFMs: `net11.0;net10.0` on Linux; adds `net48` on Windows. +- Benchmark TFMs: `net11.0;net10.0`. - Central package management via `Directory.Packages.props` (`ManagePackageVersionsCentrally=true`). - CI runs on Linux (ubuntu-24.04) and Windows (windows-2025), both X64 and ARM64. -- TFM compatibility is mandatory: proposals and code changes must work for all source TFMs. Do not assume `net9.0`/`net10.0` APIs exist in `netstandard2.0`; use conditional compilation (`#if NET9_0_OR_GREATER`) or compatible fallbacks where needed. +- TFM compatibility is mandatory: proposals and code changes must work for all source TFMs. Do not assume `net9.0`/`net10.0` APIs exist in `netstandard2.0`; use conditional compilation (`#if NET10_0_OR_GREATER`) or compatible fallbacks where needed. ## Build Commands diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0ee1042..36dc03dc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder. +## [11.0.0] - 2026-03-14 + +This is a major release centered on two deliberate changes: moving the Cuemon build and test matrix forward to .NET 11, and removing the temporary compatibility bridge that kept `Cuemon.Core` forwarding foundational APIs from `Cuemon.Kernel`. + +The .NET update is straightforward: `net11.0` is now part of the target matrix and `net9.0` is no longer supported. The more important part is the assembly boundary change. Version 10.5.0 introduced `Cuemon.Kernel` while keeping `Cuemon.Core` backward compatible through `[TypeForwardedTo]`. Starting with 11.0.0, that forwarding layer is removed. + +> [!WARNING] +> Breaking change from 11.0.0 and forward: applications using foundational APIs that were previously reachable through `Cuemon.Core` must now reference `Cuemon.Kernel` directly. This includes guard/configuration/async/text primitives such as `Validator`, `Arguments`, `Patterns`, `Disposable`, `Convertible`, `Awaiter`, parser and encoding option types, as well as date and range primitives such as `DateSpan`, `DateTimeRange`, `Range`, `TimeRange`, and `TimeUnit`. + +### Changed + +- Solution, source, test, and benchmark target frameworks now include `net11.0`; `net9.0` has been removed from the supported matrix. +- Central package management was updated to align `net11.0` and `netstandard2.0` builds with .NET 11 preview package versions, while `net10.0` remains on the .NET 10 package line where applicable. +- `DateSpan`, `DateTimeRange`, `Range`, `TimeRange`, and `TimeUnit` source files now live in `Cuemon.Kernel` as part of the completed kernel split. +- `BufferWriterOptions` was updated to follow the new `NET10_0_OR_GREATER` conditional path. +- Solution organization now groups `Cuemon.Core` and `Cuemon.Kernel` under a dedicated `/src/corelibs/` folder. +- Test environment definitions now target Docker images for `net10` and `net11`. + +### Removed + +- `Cuemon.Core` no longer uses `[TypeForwardedTo]` to forward foundational `Cuemon.Kernel` types, making the kernel split a true assembly boundary instead of a compatibility shim. + + ## [10.5.0] - 2026-03-13 Okay, so this might look like a major release — and effort-wise it certainly felt like one — but it's actually a fully backward-compatible minor bump. Thanks to a helping hand from AI and a long-standing wish to carve out a small, lean core from Cuemon, we've introduced a brand-new assembly: **Cuemon.Kernel**. Think of it as the nano (or at least noticeably smaller) sibling of `Cuemon.Core`, shipping only the most essential and much-loved types — validators, conditions, decorators, disposable patterns, the options/parameter-object infrastructure, text encoding helpers and async primitives. diff --git a/Cuemon.slnx b/Cuemon.slnx index 044f05386..eed44276c 100644 --- a/Cuemon.slnx +++ b/Cuemon.slnx @@ -9,7 +9,6 @@ - @@ -39,7 +38,6 @@ - @@ -47,6 +45,10 @@ + + + + diff --git a/Directory.Build.props b/Directory.Build.props index 7cc7eadc7..fe7db858d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -18,7 +18,7 @@ - net10.0;net9.0;netstandard2.0 + net11.0;net10.0;netstandard2.0 Copyright © Geekle 2009-2026. All rights reserved. gimlichael Geekle @@ -57,11 +57,11 @@ - net10.0;net9.0 + net11.0;net10.0 - net10.0;net9.0;net48 + net11.0;net10.0;net48 @@ -111,7 +111,7 @@ - net10.0;net9.0 + net11.0;net10.0 false false false diff --git a/Directory.Packages.props b/Directory.Packages.props index d827e75f8..3ff4cedfa 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -22,33 +22,33 @@ - + - - - - - + + + + + + - - - - - - - - - + - - + + + + + + + + + \ No newline at end of file diff --git a/src/Cuemon.AspNetCore.App/Cuemon.AspNetCore.App.csproj b/src/Cuemon.AspNetCore.App/Cuemon.AspNetCore.App.csproj index af93e5f40..47ca36444 100644 --- a/src/Cuemon.AspNetCore.App/Cuemon.AspNetCore.App.csproj +++ b/src/Cuemon.AspNetCore.App/Cuemon.AspNetCore.App.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 240bdf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.AspNetCore.Authentication/Cuemon.AspNetCore.Authentication.csproj b/src/Cuemon.AspNetCore.Authentication/Cuemon.AspNetCore.Authentication.csproj index b469274a0..48d46993f 100644 --- a/src/Cuemon.AspNetCore.Authentication/Cuemon.AspNetCore.Authentication.csproj +++ b/src/Cuemon.AspNetCore.Authentication/Cuemon.AspNetCore.Authentication.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 a10adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.AspNetCore.Mvc/Cuemon.AspNetCore.Mvc.csproj b/src/Cuemon.AspNetCore.Mvc/Cuemon.AspNetCore.Mvc.csproj index f9c2d9984..6086e201f 100644 --- a/src/Cuemon.AspNetCore.Mvc/Cuemon.AspNetCore.Mvc.csproj +++ b/src/Cuemon.AspNetCore.Mvc/Cuemon.AspNetCore.Mvc.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 a20adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.AspNetCore.Razor.TagHelpers/Cuemon.AspNetCore.Razor.TagHelpers.csproj b/src/Cuemon.AspNetCore.Razor.TagHelpers/Cuemon.AspNetCore.Razor.TagHelpers.csproj index 2d28379b7..6490f2f2a 100644 --- a/src/Cuemon.AspNetCore.Razor.TagHelpers/Cuemon.AspNetCore.Razor.TagHelpers.csproj +++ b/src/Cuemon.AspNetCore.Razor.TagHelpers/Cuemon.AspNetCore.Razor.TagHelpers.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 a30adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.AspNetCore/Cuemon.AspNetCore.csproj b/src/Cuemon.AspNetCore/Cuemon.AspNetCore.csproj index f3bc7af39..e6bc05aff 100644 --- a/src/Cuemon.AspNetCore/Cuemon.AspNetCore.csproj +++ b/src/Cuemon.AspNetCore/Cuemon.AspNetCore.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 a00adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.Core/Properties/AssemblyInfo.cs b/src/Cuemon.Core/Properties/AssemblyInfo.cs index fcf48d89a..85c554583 100644 --- a/src/Cuemon.Core/Properties/AssemblyInfo.cs +++ b/src/Cuemon.Core/Properties/AssemblyInfo.cs @@ -1,84 +1,4 @@ -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Cuemon; -using Cuemon.Collections.Generic; -using Cuemon.Configuration; -using Cuemon.IO; -using Cuemon.Text; -using Cuemon.Threading; [assembly: ComVisible(false)] [assembly: Guid("989939cf-cef2-4e23-8bce-725255e35ce6")] -[assembly: TypeForwardedTo(typeof(Alphanumeric))] -[assembly: TypeForwardedTo(typeof(ArgumentReservedKeywordException))] -[assembly: TypeForwardedTo(typeof(Arguments))] -[assembly: TypeForwardedTo(typeof(AsyncOptions))] -[assembly: TypeForwardedTo(typeof(AsyncRunOptions))] -[assembly: TypeForwardedTo(typeof(Awaiter))] -[assembly: TypeForwardedTo(typeof(ByteOrderMark))] -[assembly: TypeForwardedTo(typeof(CasingMethod))] -[assembly: TypeForwardedTo(typeof(Condition))] -[assembly: TypeForwardedTo(typeof(ConditionalValue))] -[assembly: TypeForwardedTo(typeof(ConditionalValue<>))] -[assembly: TypeForwardedTo(typeof(Convertible))] -[assembly: TypeForwardedTo(typeof(ConvertibleConverterDictionary))] -[assembly: TypeForwardedTo(typeof(ConvertibleOptions))] -[assembly: TypeForwardedTo(typeof(Decorator))] -[assembly: TypeForwardedTo(typeof(Decorator<>))] -[assembly: TypeForwardedTo(typeof(Disposable))] -[assembly: TypeForwardedTo(typeof(DisposableOptions))] -[assembly: TypeForwardedTo(typeof(EndianOptions))] -[assembly: TypeForwardedTo(typeof(EncodingOptions))] -[assembly: TypeForwardedTo(typeof(Endianness))] -[assembly: TypeForwardedTo(typeof(EnumStringOptions))] -[assembly: TypeForwardedTo(typeof(ExceptionCondition<>))] -[assembly: TypeForwardedTo(typeof(ExceptionHandler<>))] -[assembly: TypeForwardedTo(typeof(ExceptionHandler<,>))] -[assembly: TypeForwardedTo(typeof(ExceptionInvoker<>))] -[assembly: TypeForwardedTo(typeof(ExceptionInvoker<,>))] -[assembly: TypeForwardedTo(typeof(FallbackEncodingOptions))] -[assembly: TypeForwardedTo(typeof(FinalizeDisposable))] -[assembly: TypeForwardedTo(typeof(GuidFormats))] -[assembly: TypeForwardedTo(typeof(IAsyncOptions))] -[assembly: TypeForwardedTo(typeof(IConfigurableParser<>))] -[assembly: TypeForwardedTo(typeof(IConfigurableParser<,>))] -[assembly: TypeForwardedTo(typeof(IDecorator<>))] -[assembly: TypeForwardedTo(typeof(IEncodingOptions))] -[assembly: TypeForwardedTo(typeof(IParameterObject))] -[assembly: TypeForwardedTo(typeof(IParser))] -[assembly: TypeForwardedTo(typeof(IParser<>))] -[assembly: TypeForwardedTo(typeof(IPostConfigurableParameterObject))] -[assembly: TypeForwardedTo(typeof(IValidatableParameterObject))] -[assembly: TypeForwardedTo(typeof(Patterns))] -[assembly: TypeForwardedTo(typeof(PreambleSequence))] -[assembly: TypeForwardedTo(typeof(ProtocolRelativeUriStringOptions))] -[assembly: TypeForwardedTo(typeof(StreamDecoratorExtensions))] -[assembly: TypeForwardedTo(typeof(SuccessfulValue))] -[assembly: TypeForwardedTo(typeof(SuccessfulValue<>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TesterFunc<,,,,,,,,,,,,,,,,,>))] -[assembly: TypeForwardedTo(typeof(TypeArgumentException))] -[assembly: TypeForwardedTo(typeof(TypeArgumentOutOfRangeException))] -[assembly: TypeForwardedTo(typeof(UnsuccessfulValue))] -[assembly: TypeForwardedTo(typeof(UnsuccessfulValue<>))] -[assembly: TypeForwardedTo(typeof(UriScheme))] -[assembly: TypeForwardedTo(typeof(UriStringOptions))] -[assembly: TypeForwardedTo(typeof(Validator))] -#if !NETCOREAPP3_0_OR_GREATER -[assembly: TypeForwardedTo(typeof(CallerArgumentExpressionAttribute))] -#endif diff --git a/src/Cuemon.Core/Reflection/AssemblyContext.cs b/src/Cuemon.Core/Reflection/AssemblyContext.cs index af4588311..580557366 100644 --- a/src/Cuemon.Core/Reflection/AssemblyContext.cs +++ b/src/Cuemon.Core/Reflection/AssemblyContext.cs @@ -67,7 +67,7 @@ private static IEnumerable GetReferencedAssemblies(Assembly assembly, private static bool TryPop(Stack stack, out Assembly assembly) { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER return stack.TryPop(out assembly); #else return Decorator.RawEnclose(stack).TryPop(out assembly); diff --git a/src/Cuemon.Core/Runtime/Dependency.cs b/src/Cuemon.Core/Runtime/Dependency.cs index cb77dae6c..69c75d6c1 100644 --- a/src/Cuemon.Core/Runtime/Dependency.cs +++ b/src/Cuemon.Core/Runtime/Dependency.cs @@ -12,7 +12,7 @@ public abstract class Dependency : IDependency { private IEnumerable _watchers; private readonly Func, IEnumerable> _watchersHandler; -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER private readonly System.Threading.Lock _lock = new(); #else private readonly object _lock = new(); diff --git a/src/Cuemon.Core/Runtime/FileWatcher.cs b/src/Cuemon.Core/Runtime/FileWatcher.cs index a1fccd309..2e7f9b137 100644 --- a/src/Cuemon.Core/Runtime/FileWatcher.cs +++ b/src/Cuemon.Core/Runtime/FileWatcher.cs @@ -11,7 +11,7 @@ namespace Cuemon.Runtime /// public class FileWatcher : Watcher { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER private readonly System.Threading.Lock _lock = new(); #else private readonly object _lock = new(); diff --git a/src/Cuemon.Core/Runtime/Watcher.cs b/src/Cuemon.Core/Runtime/Watcher.cs index f3a6c938b..9a13059f0 100644 --- a/src/Cuemon.Core/Runtime/Watcher.cs +++ b/src/Cuemon.Core/Runtime/Watcher.cs @@ -10,7 +10,7 @@ namespace Cuemon.Runtime /// public abstract class Watcher : Disposable, IWatcher { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER private readonly Lock _lock = new(); #else private readonly object _lock = new(); diff --git a/src/Cuemon.Core/StringFactory.cs b/src/Cuemon.Core/StringFactory.cs index d7adaa19f..cb87aa68a 100644 --- a/src/Cuemon.Core/StringFactory.cs +++ b/src/Cuemon.Core/StringFactory.cs @@ -24,7 +24,7 @@ public static class StringFactory public static string CreateHexadecimal(byte[] value) { Validator.ThrowIfNull(value); -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER return Convert.ToHexString(value).Replace("-", "").ToLowerInvariant(); #else return BitConverter.ToString(value).Replace("-", "").ToLowerInvariant(); diff --git a/src/Cuemon.Data/DatabaseWatcher.cs b/src/Cuemon.Data/DatabaseWatcher.cs index dbbadc35b..556239552 100644 --- a/src/Cuemon.Data/DatabaseWatcher.cs +++ b/src/Cuemon.Data/DatabaseWatcher.cs @@ -14,7 +14,7 @@ namespace Cuemon.Data /// public class DatabaseWatcher : Watcher { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER private readonly System.Threading.Lock _lock = new(); #else private readonly object _lock = new(); diff --git a/src/Cuemon.Extensions.AspNetCore.Authentication/Cuemon.Extensions.AspNetCore.Authentication.csproj b/src/Cuemon.Extensions.AspNetCore.Authentication/Cuemon.Extensions.AspNetCore.Authentication.csproj index cdbf53662..c5f8e11bf 100644 --- a/src/Cuemon.Extensions.AspNetCore.Authentication/Cuemon.Extensions.AspNetCore.Authentication.csproj +++ b/src/Cuemon.Extensions.AspNetCore.Authentication/Cuemon.Extensions.AspNetCore.Authentication.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 220bdf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.csproj b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.csproj index bffb58818..566e92b43 100644 --- a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.csproj +++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 a90adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj index 813ab95b8..747080e25 100644 --- a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj +++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 a70adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.csproj b/src/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.csproj index fcbd21aea..8fefe9001 100644 --- a/src/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.csproj +++ b/src/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 c6b592e8-2413-4bff-adf2-8a72c62199e3 diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Cuemon.Extensions.AspNetCore.Mvc.csproj b/src/Cuemon.Extensions.AspNetCore.Mvc/Cuemon.Extensions.AspNetCore.Mvc.csproj index b6ab1e073..c018690fa 100644 --- a/src/Cuemon.Extensions.AspNetCore.Mvc/Cuemon.Extensions.AspNetCore.Mvc.csproj +++ b/src/Cuemon.Extensions.AspNetCore.Mvc/Cuemon.Extensions.AspNetCore.Mvc.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 a50adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.Extensions.AspNetCore.Text.Json/Cuemon.Extensions.AspNetCore.Text.Json.csproj b/src/Cuemon.Extensions.AspNetCore.Text.Json/Cuemon.Extensions.AspNetCore.Text.Json.csproj index 9d8cab49e..920c2b81c 100644 --- a/src/Cuemon.Extensions.AspNetCore.Text.Json/Cuemon.Extensions.AspNetCore.Text.Json.csproj +++ b/src/Cuemon.Extensions.AspNetCore.Text.Json/Cuemon.Extensions.AspNetCore.Text.Json.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 ae0adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.Extensions.AspNetCore.Xml/Cuemon.Extensions.AspNetCore.Xml.csproj b/src/Cuemon.Extensions.AspNetCore.Xml/Cuemon.Extensions.AspNetCore.Xml.csproj index e12538b0e..4835fe5b2 100644 --- a/src/Cuemon.Extensions.AspNetCore.Xml/Cuemon.Extensions.AspNetCore.Xml.csproj +++ b/src/Cuemon.Extensions.AspNetCore.Xml/Cuemon.Extensions.AspNetCore.Xml.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 af0adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.Extensions.AspNetCore/Cuemon.Extensions.AspNetCore.csproj b/src/Cuemon.Extensions.AspNetCore/Cuemon.Extensions.AspNetCore.csproj index 1fc096291..11f161f12 100644 --- a/src/Cuemon.Extensions.AspNetCore/Cuemon.Extensions.AspNetCore.csproj +++ b/src/Cuemon.Extensions.AspNetCore/Cuemon.Extensions.AspNetCore.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 a40adf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.Extensions.IO/Cuemon.Extensions.IO.csproj b/src/Cuemon.Extensions.IO/Cuemon.Extensions.IO.csproj index c0de63fff..f565b191d 100644 --- a/src/Cuemon.Extensions.IO/Cuemon.Extensions.IO.csproj +++ b/src/Cuemon.Extensions.IO/Cuemon.Extensions.IO.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0;netstandard2.1;netstandard2.0 + net11.0;net10.0;netstandard2.1;netstandard2.0 060bdf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.Extensions.IO/StreamExtensions.cs b/src/Cuemon.Extensions.IO/StreamExtensions.cs index 4134b4d48..2c9d18201 100644 --- a/src/Cuemon.Extensions.IO/StreamExtensions.cs +++ b/src/Cuemon.Extensions.IO/StreamExtensions.cs @@ -197,7 +197,7 @@ public static Task ToEncodedStringAsync(this Stream value, Action /// Compresses the using the BROTLI algorithm. @@ -312,7 +312,7 @@ public static Task CompressGZipAsync(this Stream value, Action /// Decompresses the using the BROTLI data format specification. diff --git a/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs b/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs index 17ae2b916..3f9ef9f96 100644 --- a/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs +++ b/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs @@ -7,7 +7,7 @@ namespace Cuemon.Extensions.Net.Http { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER /// /// Provides a simple and lightweight implementation of the interface. /// @@ -22,14 +22,14 @@ namespace Cuemon.Extensions.Net.Http /// Inspiration taken from https://github.com/dotnet/runtime/blob/master/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpClientFactory.cs #endif public class SlimHttpClientFactory : IHttpClientFactory -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER , IHttpMessageHandlerFactory #endif { private readonly ConcurrentDictionary> _activeHandlers = new(); private readonly ConcurrentQueue _expiredHandlers = new(); private readonly Func _handlerFactory; -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER private readonly Lock _lock = new(); #else private readonly object _lock = new(); diff --git a/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs b/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs index 0ea42d440..bf26a5723 100644 --- a/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs +++ b/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs @@ -712,7 +712,7 @@ public static Func Memoize { diff --git a/src/Cuemon.Extensions.Text.Json/Formatters/JsonFormatterOptions.cs b/src/Cuemon.Extensions.Text.Json/Formatters/JsonFormatterOptions.cs index a5747ef5c..0833cc205 100644 --- a/src/Cuemon.Extensions.Text.Json/Formatters/JsonFormatterOptions.cs +++ b/src/Cuemon.Extensions.Text.Json/Formatters/JsonFormatterOptions.cs @@ -16,7 +16,7 @@ namespace Cuemon.Extensions.Text.Json.Formatters /// public class JsonFormatterOptions : IContentNegotiation, IExceptionDescriptorOptions, IValidatableParameterObject { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER private readonly System.Threading.Lock _lock = new(); #else private readonly object _lock = new(); diff --git a/src/Cuemon.IO/BufferWriterOptions.cs b/src/Cuemon.IO/BufferWriterOptions.cs index 86ea5de1e..ec7268ef4 100644 --- a/src/Cuemon.IO/BufferWriterOptions.cs +++ b/src/Cuemon.IO/BufferWriterOptions.cs @@ -1,4 +1,4 @@ -#if NETSTANDARD2_1_OR_GREATER || NET9_0_OR_GREATER +#if NETSTANDARD2_1_OR_GREATER || NET10_0_OR_GREATER using System.Buffers; using Cuemon.Text; diff --git a/src/Cuemon.IO/Cuemon.IO.csproj b/src/Cuemon.IO/Cuemon.IO.csproj index 8dfa5a5a3..d15b13f84 100644 --- a/src/Cuemon.IO/Cuemon.IO.csproj +++ b/src/Cuemon.IO/Cuemon.IO.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0;netstandard2.1;netstandard2.0 + net11.0;net10.0;netstandard2.1;netstandard2.0 170bdf91-e7c7-4cb4-a39d-e1a5374c5602 diff --git a/src/Cuemon.IO/Extensions/StreamDecoratorExtensions.cs b/src/Cuemon.IO/Extensions/StreamDecoratorExtensions.cs index f95e6be1d..bfd698b8e 100644 --- a/src/Cuemon.IO/Extensions/StreamDecoratorExtensions.cs +++ b/src/Cuemon.IO/Extensions/StreamDecoratorExtensions.cs @@ -204,7 +204,7 @@ private static async Task ToEncodedStringAsyncCore(this IDecorator /// Compress the enclosed of the specified using the Brotli algorithm. @@ -461,7 +461,7 @@ private static Task CompressAsync(IDecorator decorator, Async { return AsyncPatterns.SafeInvokeAsync(() => new MemoryStream(), async (target, ct) => { -#if NETSTANDARD2_1_OR_GREATER || NET9_0_OR_GREATER +#if NETSTANDARD2_1_OR_GREATER || NET10_0_OR_GREATER await using (var compressed = decompressor(target, options.Level, true)) { await Decorator.Enclose(decorator.Inner).CopyStreamAsync(compressed, options.BufferSize, ct: ct).ConfigureAwait(false); @@ -497,7 +497,7 @@ private static Task DecompressAsync(IDecorator decorator, Asy { return AsyncPatterns.SafeInvokeAsync(() => new MemoryStream(), async (target, ct) => { -#if NETSTANDARD2_1_OR_GREATER || NET9_0_OR_GREATER +#if NETSTANDARD2_1_OR_GREATER || NET10_0_OR_GREATER await using (var uncompressed = compressor(decorator.Inner, CompressionMode.Decompress, true)) { await Decorator.Enclose(uncompressed).CopyStreamAsync(target, options.BufferSize, ct: ct).ConfigureAwait(false); diff --git a/src/Cuemon.IO/StreamFactory.cs b/src/Cuemon.IO/StreamFactory.cs index 6c44e71e3..898a94160 100644 --- a/src/Cuemon.IO/StreamFactory.cs +++ b/src/Cuemon.IO/StreamFactory.cs @@ -1,5 +1,5 @@ using System; -#if NETSTANDARD2_1_OR_GREATER || NET9_0_OR_GREATER +#if NETSTANDARD2_1_OR_GREATER || NET10_0_OR_GREATER using System.Buffers; #endif using System.Collections.Generic; @@ -115,7 +115,7 @@ public static Stream Create(Action /// Creates and returns a by the specified delegate . diff --git a/src/Cuemon.Kernel/Convertible.cs b/src/Cuemon.Kernel/Convertible.cs index ac5b24f07..7dfb54374 100644 --- a/src/Cuemon.Kernel/Convertible.cs +++ b/src/Cuemon.Kernel/Convertible.cs @@ -301,7 +301,7 @@ public static byte[] GetBytes(long input, Action setup = null) /// A byte array that represents . public static byte[] GetBytes(sbyte input, Action setup = null) { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER return GetBytesCore(input, x => BitConverter.GetBytes((short)x), setup); #else return GetBytesCore(input, x => BitConverter.GetBytes(x), setup); diff --git a/src/Cuemon.Core/DateSpan.cs b/src/Cuemon.Kernel/DateSpan.cs similarity index 98% rename from src/Cuemon.Core/DateSpan.cs rename to src/Cuemon.Kernel/DateSpan.cs index 270f574e4..3fe8e52f5 100644 --- a/src/Cuemon.Core/DateSpan.cs +++ b/src/Cuemon.Kernel/DateSpan.cs @@ -1,8 +1,7 @@ -using System; +using System; using System.Globalization; using System.Linq; using Cuemon.Collections.Generic; -using Cuemon.Security; namespace Cuemon { @@ -15,8 +14,8 @@ namespace Cuemon private readonly DateTime _upper; private readonly Calendar _calendar; private readonly ulong _calendarId; - private static readonly ulong Hash = (ulong)new FowlerNollVo64().OffsetBasis; - private static readonly ulong Prime = (ulong)new FowlerNollVo64().Prime; + private const ulong Hash = 14695981039346656037; + private const ulong Prime = 1099511628211; /// /// Initializes a new instance of the structure with a default value set to . diff --git a/src/Cuemon.Core/DateTimeRange.cs b/src/Cuemon.Kernel/DateTimeRange.cs similarity index 98% rename from src/Cuemon.Core/DateTimeRange.cs rename to src/Cuemon.Kernel/DateTimeRange.cs index a73b55abc..28c1812ea 100644 --- a/src/Cuemon.Core/DateTimeRange.cs +++ b/src/Cuemon.Kernel/DateTimeRange.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; namespace Cuemon @@ -26,4 +26,4 @@ public override string ToString() return ToString("s", CultureInfo.InvariantCulture); } } -} \ No newline at end of file +} diff --git a/src/Cuemon.Kernel/Disposable.cs b/src/Cuemon.Kernel/Disposable.cs index 9def0e99d..08aaad2a3 100644 --- a/src/Cuemon.Kernel/Disposable.cs +++ b/src/Cuemon.Kernel/Disposable.cs @@ -8,7 +8,7 @@ namespace Cuemon /// public abstract class Disposable : IDisposable { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER private readonly System.Threading.Lock _lock = new(); #else private readonly object _lock = new(); diff --git a/src/Cuemon.Core/Range.cs b/src/Cuemon.Kernel/Range.cs similarity index 100% rename from src/Cuemon.Core/Range.cs rename to src/Cuemon.Kernel/Range.cs diff --git a/src/Cuemon.Core/TimeRange.cs b/src/Cuemon.Kernel/TimeRange.cs similarity index 67% rename from src/Cuemon.Core/TimeRange.cs rename to src/Cuemon.Kernel/TimeRange.cs index 4b2d43616..cc3302191 100644 --- a/src/Cuemon.Core/TimeRange.cs +++ b/src/Cuemon.Kernel/TimeRange.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; namespace Cuemon @@ -13,11 +13,8 @@ public class TimeRange : Range /// /// The start of a time range. /// The end of a time range. - public TimeRange(TimeSpan start, TimeSpan end) : this(start, end, () => end.Subtract(start)) - { - } - - internal TimeRange(TimeSpan start, TimeSpan end, Func duration) : base(start, end, duration) + /// A function delegate that returns the duration of the time range. If not provided, the duration is calculated as the difference between and . + public TimeRange(TimeSpan start, TimeSpan end, Func duration = null) : base(start, end, duration ?? (() => end.Subtract(start))) { } @@ -30,4 +27,4 @@ public override string ToString() return ToString("c", CultureInfo.InvariantCulture); } } -} \ No newline at end of file +} diff --git a/src/Cuemon.Core/TimeUnit.cs b/src/Cuemon.Kernel/TimeUnit.cs similarity index 100% rename from src/Cuemon.Core/TimeUnit.cs rename to src/Cuemon.Kernel/TimeUnit.cs diff --git a/src/Cuemon.Resilience/Transient.cs b/src/Cuemon.Resilience/Transient.cs index d0e407403..ffba3718a 100644 --- a/src/Cuemon.Resilience/Transient.cs +++ b/src/Cuemon.Resilience/Transient.cs @@ -8,7 +8,7 @@ namespace Cuemon.Resilience { internal abstract class Transient where TOptions : TransientOperationOptions, new() { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER protected readonly System.Threading.Lock _lock = new(); #else protected readonly object _lock = new(); diff --git a/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs b/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs index 7ea3beb10..4ce09db02 100644 --- a/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs +++ b/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs @@ -14,7 +14,7 @@ namespace Cuemon.Xml.Serialization.Formatters /// public class XmlFormatterOptions : IExceptionDescriptorOptions, IContentNegotiation, IValidatableParameterObject { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER private readonly System.Threading.Lock _lock = new(); #else private readonly object _lock = new(); diff --git a/test/Cuemon.AspNetCore.Authentication.Tests/Cuemon.AspNetCore.Authentication.Tests.csproj b/test/Cuemon.AspNetCore.Authentication.Tests/Cuemon.AspNetCore.Authentication.Tests.csproj index 3c085ffa8..1596bc2ca 100644 --- a/test/Cuemon.AspNetCore.Authentication.Tests/Cuemon.AspNetCore.Authentication.Tests.csproj +++ b/test/Cuemon.AspNetCore.Authentication.Tests/Cuemon.AspNetCore.Authentication.Tests.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 Cuemon.AspNetCore.Authentication diff --git a/test/Cuemon.AspNetCore.FunctionalTests/Cuemon.AspNetCore.FunctionalTests.csproj b/test/Cuemon.AspNetCore.FunctionalTests/Cuemon.AspNetCore.FunctionalTests.csproj index d5d402a2d..d0dc61003 100644 --- a/test/Cuemon.AspNetCore.FunctionalTests/Cuemon.AspNetCore.FunctionalTests.csproj +++ b/test/Cuemon.AspNetCore.FunctionalTests/Cuemon.AspNetCore.FunctionalTests.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 Cuemon.AspNetCore diff --git a/test/Cuemon.AspNetCore.Mvc.FunctionalTests/Cuemon.AspNetCore.Mvc.FunctionalTests.csproj b/test/Cuemon.AspNetCore.Mvc.FunctionalTests/Cuemon.AspNetCore.Mvc.FunctionalTests.csproj index f080a87a9..502253f9f 100644 --- a/test/Cuemon.AspNetCore.Mvc.FunctionalTests/Cuemon.AspNetCore.Mvc.FunctionalTests.csproj +++ b/test/Cuemon.AspNetCore.Mvc.FunctionalTests/Cuemon.AspNetCore.Mvc.FunctionalTests.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 Cuemon.AspNetCore.Mvc diff --git a/test/Cuemon.AspNetCore.Mvc.Tests/Cuemon.AspNetCore.Mvc.Tests.csproj b/test/Cuemon.AspNetCore.Mvc.Tests/Cuemon.AspNetCore.Mvc.Tests.csproj index 4595db461..2e0820671 100644 --- a/test/Cuemon.AspNetCore.Mvc.Tests/Cuemon.AspNetCore.Mvc.Tests.csproj +++ b/test/Cuemon.AspNetCore.Mvc.Tests/Cuemon.AspNetCore.Mvc.Tests.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 Cuemon.AspNetCore.Mvc diff --git a/test/Cuemon.AspNetCore.Razor.TagHelpers.Tests/Cuemon.AspNetCore.Razor.TagHelpers.Tests.csproj b/test/Cuemon.AspNetCore.Razor.TagHelpers.Tests/Cuemon.AspNetCore.Razor.TagHelpers.Tests.csproj index 85f963dca..69dc604f6 100644 --- a/test/Cuemon.AspNetCore.Razor.TagHelpers.Tests/Cuemon.AspNetCore.Razor.TagHelpers.Tests.csproj +++ b/test/Cuemon.AspNetCore.Razor.TagHelpers.Tests/Cuemon.AspNetCore.Razor.TagHelpers.Tests.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 Cuemon.AspNetCore.Razor.TagHelpers diff --git a/test/Cuemon.AspNetCore.Tests/Cuemon.AspNetCore.Tests.csproj b/test/Cuemon.AspNetCore.Tests/Cuemon.AspNetCore.Tests.csproj index 1c681bceb..e3e793a31 100644 --- a/test/Cuemon.AspNetCore.Tests/Cuemon.AspNetCore.Tests.csproj +++ b/test/Cuemon.AspNetCore.Tests/Cuemon.AspNetCore.Tests.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 Cuemon.AspNetCore diff --git a/test/Cuemon.Core.Tests/Assets/ClampOptions.cs b/test/Cuemon.Core.Tests/Assets/ClampOptions.cs index ab0a1a958..665073ba3 100644 --- a/test/Cuemon.Core.Tests/Assets/ClampOptions.cs +++ b/test/Cuemon.Core.Tests/Assets/ClampOptions.cs @@ -16,7 +16,7 @@ public int MaxConcurrentJobs get => _maxConcurrentJobs; set { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER _maxConcurrentJobs = Math.Clamp(value, 1, byte.MaxValue); #else _maxConcurrentJobs = Clamp(value, 1, byte.MaxValue); diff --git a/test/Cuemon.Core.Tests/Assets/UnmanagedDisposable.cs b/test/Cuemon.Core.Tests/Assets/UnmanagedDisposable.cs index a0bd688f1..f6259c8ce 100644 --- a/test/Cuemon.Core.Tests/Assets/UnmanagedDisposable.cs +++ b/test/Cuemon.Core.Tests/Assets/UnmanagedDisposable.cs @@ -28,7 +28,7 @@ public delegate IntPtr CreateFileDelegate(string lpFileName, public UnmanagedDisposable() { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER if (Environment.OSVersion.Platform == PlatformID.Win32NT) { if (NativeLibrary.TryLoad("kernel32.dll", GetType().Assembly, DllImportSearchPath.System32, out _libHandle)) @@ -84,7 +84,7 @@ protected override void OnDisposeManagedResources() protected override void OnDisposeUnmanagedResources() { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER if (Environment.OSVersion.Platform == PlatformID.Win32NT) { if (_handle != IntPtr.Zero) diff --git a/test/Cuemon.Core.Tests/Reflection/AssemblyContextOptionsTest.cs b/test/Cuemon.Core.Tests/Reflection/AssemblyContextOptionsTest.cs index 4ec04f5ec..c57864295 100644 --- a/test/Cuemon.Core.Tests/Reflection/AssemblyContextOptionsTest.cs +++ b/test/Cuemon.Core.Tests/Reflection/AssemblyContextOptionsTest.cs @@ -117,7 +117,7 @@ public void DefaultAssemblyFilter_ShouldReturnSameResult_WhenCalledMultipleTimes Assert.Equal(second, third); } -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER [Fact] public void DefaultAssemblyFilter_ShouldIncludeNonSystemNonMicrosoftAssemblies() { diff --git a/test/Cuemon.Core.Tests/Text/ParserFactoryTest.cs b/test/Cuemon.Core.Tests/Text/ParserFactoryTest.cs index 818bac35d..6c8405f85 100644 --- a/test/Cuemon.Core.Tests/Text/ParserFactoryTest.cs +++ b/test/Cuemon.Core.Tests/Text/ParserFactoryTest.cs @@ -82,7 +82,7 @@ public void ParserFactory_ShouldConvertString_ToTypeConverterImplementation() var sg = Guid.NewGuid(); Assert.Equal(sg, ParserFactory.FromObject().Parse(sg.ToString())); -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER var v = new Version(); Assert.Equal(v, ParserFactory.FromObject().Parse(v.ToString(), typeof(Version))); #endif diff --git a/test/Cuemon.Extensions.AspNetCore.Authentication.Tests/Cuemon.Extensions.AspNetCore.Authentication.Tests.csproj b/test/Cuemon.Extensions.AspNetCore.Authentication.Tests/Cuemon.Extensions.AspNetCore.Authentication.Tests.csproj index 8dc114d1b..8aed2b0cc 100644 --- a/test/Cuemon.Extensions.AspNetCore.Authentication.Tests/Cuemon.Extensions.AspNetCore.Authentication.Tests.csproj +++ b/test/Cuemon.Extensions.AspNetCore.Authentication.Tests/Cuemon.Extensions.AspNetCore.Authentication.Tests.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 Cuemon.Extensions.AspNetCore.Authentication diff --git a/test/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.Tests/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.Tests.csproj b/test/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.Tests/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.Tests.csproj index 354d7beba..c446fcda1 100644 --- a/test/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.Tests/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.Tests.csproj +++ b/test/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.Tests/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.Tests.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json diff --git a/test/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Tests/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Tests.csproj b/test/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Tests/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Tests.csproj index 2cbae3999..a1e513e9a 100644 --- a/test/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Tests/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Tests.csproj +++ b/test/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Tests/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Tests.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml diff --git a/test/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.Tests/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.Tests.csproj b/test/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.Tests/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.Tests.csproj index cc5f43d91..10851956d 100644 --- a/test/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.Tests/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.Tests.csproj +++ b/test/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.Tests/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.Tests.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 Cuemon.Extensions.AspNetCore.Mvc.RazorPages diff --git a/test/Cuemon.Extensions.AspNetCore.Mvc.Tests/Cuemon.Extensions.AspNetCore.Mvc.Tests.csproj b/test/Cuemon.Extensions.AspNetCore.Mvc.Tests/Cuemon.Extensions.AspNetCore.Mvc.Tests.csproj index 38bbda6ac..ae56e6ac7 100644 --- a/test/Cuemon.Extensions.AspNetCore.Mvc.Tests/Cuemon.Extensions.AspNetCore.Mvc.Tests.csproj +++ b/test/Cuemon.Extensions.AspNetCore.Mvc.Tests/Cuemon.Extensions.AspNetCore.Mvc.Tests.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 Cuemon.Extensions.AspNetCore.Mvc true diff --git a/test/Cuemon.Extensions.AspNetCore.Tests/Cuemon.Extensions.AspNetCore.Tests.csproj b/test/Cuemon.Extensions.AspNetCore.Tests/Cuemon.Extensions.AspNetCore.Tests.csproj index d3e712352..1dbaf451c 100644 --- a/test/Cuemon.Extensions.AspNetCore.Tests/Cuemon.Extensions.AspNetCore.Tests.csproj +++ b/test/Cuemon.Extensions.AspNetCore.Tests/Cuemon.Extensions.AspNetCore.Tests.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0 + net11.0;net10.0 Cuemon.Extensions.AspNetCore diff --git a/test/Cuemon.Extensions.DependencyInjection.Tests/Cuemon.Extensions.DependencyInjection.Tests.csproj b/test/Cuemon.Extensions.DependencyInjection.Tests/Cuemon.Extensions.DependencyInjection.Tests.csproj index 6f0d70187..9d07b1a0c 100644 --- a/test/Cuemon.Extensions.DependencyInjection.Tests/Cuemon.Extensions.DependencyInjection.Tests.csproj +++ b/test/Cuemon.Extensions.DependencyInjection.Tests/Cuemon.Extensions.DependencyInjection.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/test/Cuemon.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionsTest.cs b/test/Cuemon.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionsTest.cs index b6fe10402..bdad99478 100644 --- a/test/Cuemon.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionsTest.cs +++ b/test/Cuemon.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionsTest.cs @@ -1,6 +1,6 @@ using System; using System.Linq; -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER using Cuemon.AspNetCore.Diagnostics; using Cuemon.AspNetCore.Mvc.Filters.Diagnostics; using Cuemon.Extensions.Text.Json.Formatters; @@ -385,7 +385,7 @@ public void TryAdd_ShouldAddServiceToServiceCollectionUsingFactoryWithSpecifiedL Assert.Null(sut9); } -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER [Fact] public void TryConfigure_ShouldAddConfigureOptions() diff --git a/test/Cuemon.Extensions.Hosting.Tests/HostEnvironmentExtensionsTest.cs b/test/Cuemon.Extensions.Hosting.Tests/HostEnvironmentExtensionsTest.cs index 00a1527ec..e8af8979f 100644 --- a/test/Cuemon.Extensions.Hosting.Tests/HostEnvironmentExtensionsTest.cs +++ b/test/Cuemon.Extensions.Hosting.Tests/HostEnvironmentExtensionsTest.cs @@ -23,7 +23,7 @@ public override void ConfigureServices(IServiceCollection services) [Fact] public void IsLocalDevelopment_VerifyEnvironmentEqualsLocalDevelopment() { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER Assert.True(Environment.IsLocalDevelopment()); Assert.False(Environment.IsProduction()); Assert.False(Environment.IsStaging()); @@ -40,7 +40,7 @@ public void IsLocalDevelopment_VerifyEnvironmentEqualsLocalDevelopment() [Fact] public void IsLocalDevelopment_VerifyEnvironmentIsNonProduction() { -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER Assert.True(Environment.IsNonProduction()); Assert.False(Environment.IsProduction()); #else diff --git a/test/Cuemon.Extensions.IO.Tests/StreamExtensionsTest.cs b/test/Cuemon.Extensions.IO.Tests/StreamExtensionsTest.cs index 1077cd088..cf1de4496 100644 --- a/test/Cuemon.Extensions.IO.Tests/StreamExtensionsTest.cs +++ b/test/Cuemon.Extensions.IO.Tests/StreamExtensionsTest.cs @@ -218,7 +218,7 @@ public async Task ToEncodedStringAsync_ShouldConvertStreamToUnicodeEncodedString Assert.Equal(636, sut6.Length); } -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER [Fact] public void CompressBrotli_ShouldCompressAndDecompress() diff --git a/test/Cuemon.Extensions.IO.Tests/TextReaderExtensionsTest.cs b/test/Cuemon.Extensions.IO.Tests/TextReaderExtensionsTest.cs index ab0778ba9..8a0fd37c3 100644 --- a/test/Cuemon.Extensions.IO.Tests/TextReaderExtensionsTest.cs +++ b/test/Cuemon.Extensions.IO.Tests/TextReaderExtensionsTest.cs @@ -25,7 +25,7 @@ public async Task CopyToAsync_ShouldCopyContentOfReaderToWriter() sut2.Dispose(); -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER await sut3.DisposeAsync(); await sut4.DisposeAsync(); #else diff --git a/test/Cuemon.Extensions.Reflection.Tests/TypeExtensionsTest.cs b/test/Cuemon.Extensions.Reflection.Tests/TypeExtensionsTest.cs index 8750b7386..45f7c5be3 100644 --- a/test/Cuemon.Extensions.Reflection.Tests/TypeExtensionsTest.cs +++ b/test/Cuemon.Extensions.Reflection.Tests/TypeExtensionsTest.cs @@ -165,7 +165,7 @@ public void GetAllFields_ShouldIncludeFullInheritanceChainOfFields() expected = 21; actualValueName = "m_actualValue"; #endif -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER expected = 16; #endif diff --git a/test/Cuemon.Extensions.Text.Json.Tests/Cuemon.Extensions.Text.Json.Tests.csproj b/test/Cuemon.Extensions.Text.Json.Tests/Cuemon.Extensions.Text.Json.Tests.csproj index ce9ee0993..29b46473c 100644 --- a/test/Cuemon.Extensions.Text.Json.Tests/Cuemon.Extensions.Text.Json.Tests.csproj +++ b/test/Cuemon.Extensions.Text.Json.Tests/Cuemon.Extensions.Text.Json.Tests.csproj @@ -1,7 +1,7 @@ - net10.0;net9.0 + net11.0;net10.0 Cuemon.Extensions.Text.Json diff --git a/test/Cuemon.Extensions.Threading.Tests/Tasks/TaskExtensionsTest.cs b/test/Cuemon.Extensions.Threading.Tests/Tasks/TaskExtensionsTest.cs index 42a95f283..7e255d479 100644 --- a/test/Cuemon.Extensions.Threading.Tests/Tasks/TaskExtensionsTest.cs +++ b/test/Cuemon.Extensions.Threading.Tests/Tasks/TaskExtensionsTest.cs @@ -22,7 +22,7 @@ public void ContinueWithCapturedContext_ShouldHaveTaskAwaiterSetToTrue() var sut = task.ContinueWithCapturedContext(); var configuredTaskAwaiter = sut.GetType().GetField("m_configuredTaskAwaiter", MemberReflection.Everything).GetValue(sut).As(); var continueOnCapturedContext = false; -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER continueOnCapturedContext = configuredTaskAwaiter.GetType().GetField("m_options", MemberReflection.Everything)?.GetValue(configuredTaskAwaiter)?.As() == ConfigureAwaitOptions.ContinueOnCapturedContext; #else continueOnCapturedContext = configuredTaskAwaiter.GetType().GetField("m_continueOnCapturedContext", MemberReflection.Everything).GetValue(configuredTaskAwaiter).As(); @@ -44,7 +44,7 @@ public void ContinueWithSuppressedContext_ShouldHaveTaskAwaiterSetToFalse() var sut = task.ContinueWithSuppressedContext(); var configuredTaskAwaiter = sut.GetType().GetField("m_configuredTaskAwaiter", MemberReflection.Everything).GetValue(sut).As(); var continueOnCapturedContext = true; -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER continueOnCapturedContext = configuredTaskAwaiter.GetType().GetField("m_options", MemberReflection.Everything)?.GetValue(configuredTaskAwaiter)?.As() == ConfigureAwaitOptions.ContinueOnCapturedContext; #else continueOnCapturedContext = configuredTaskAwaiter.GetType().GetField("m_continueOnCapturedContext", MemberReflection.Everything).GetValue(configuredTaskAwaiter).As(); @@ -64,7 +64,7 @@ public void ContinueWithCapturedContextOfResult_ShouldHaveTaskAwaiterSetToTrue() var awaitableTask = sut.ContinueWithCapturedContext(); var configuredTaskAwaiter = awaitableTask.GetType().GetField("m_configuredTaskAwaiter", MemberReflection.Everything).GetValue(awaitableTask).As.ConfiguredTaskAwaiter>(); var continueOnCapturedContext = false; -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER continueOnCapturedContext = configuredTaskAwaiter.GetType().GetField("m_options", MemberReflection.Everything)?.GetValue(configuredTaskAwaiter)?.As() == ConfigureAwaitOptions.ContinueOnCapturedContext; #else continueOnCapturedContext = configuredTaskAwaiter.GetType().GetField("m_continueOnCapturedContext", MemberReflection.Everything).GetValue(configuredTaskAwaiter).As(); @@ -84,7 +84,7 @@ public void ContinueWithSuppressedContextOfResult_ShouldHaveTaskAwaiterSetToFals var sut = task.ContinueWithSuppressedContext(); var configuredTaskAwaiter = sut.GetType().GetField("m_configuredTaskAwaiter", MemberReflection.Everything).GetValue(sut).As.ConfiguredTaskAwaiter>(); var continueOnCapturedContext = true; -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER continueOnCapturedContext = configuredTaskAwaiter.GetType().GetField("m_options", MemberReflection.Everything)?.GetValue(configuredTaskAwaiter)?.As() == ConfigureAwaitOptions.ContinueOnCapturedContext; #else continueOnCapturedContext = configuredTaskAwaiter.GetType().GetField("m_continueOnCapturedContext", MemberReflection.Everything).GetValue(configuredTaskAwaiter).As(); diff --git a/test/Cuemon.IO.Tests/StreamDecoratorExtensionsTest.cs b/test/Cuemon.IO.Tests/StreamDecoratorExtensionsTest.cs index 68d12af8a..0abe54de4 100644 --- a/test/Cuemon.IO.Tests/StreamDecoratorExtensionsTest.cs +++ b/test/Cuemon.IO.Tests/StreamDecoratorExtensionsTest.cs @@ -16,7 +16,7 @@ public StreamDecoratorExtensionsTest(ITestOutputHelper output) : base(output) { } -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER [Fact] public void CompressBrotli_ShouldCompressAndDecompress() diff --git a/test/Cuemon.Core.Tests/DateSpanTest.cs b/test/Cuemon.Kernel.Tests/DateSpanTest.cs similarity index 56% rename from test/Cuemon.Core.Tests/DateSpanTest.cs rename to test/Cuemon.Kernel.Tests/DateSpanTest.cs index 58ae29b7e..75e361836 100644 --- a/test/Cuemon.Core.Tests/DateSpanTest.cs +++ b/test/Cuemon.Kernel.Tests/DateSpanTest.cs @@ -1,5 +1,6 @@ -using Codebelt.Extensions.Xunit; +using Codebelt.Extensions.Xunit; using System; +using System.Collections.Generic; using System.Globalization; using Xunit; @@ -219,7 +220,14 @@ public void Parse_ShouldGetNineMonthOfDifference_UsingIso8601String() public void DateSpan_ShouldHandleOverlapInMonthAndDays() { var sut0 = new DateTime(2020, 5, 12); - var sut1 = Generate.RangeOf(5, i => new DateTime(2021, 5, i + 10)); + var sut1 = new[] + { + new DateTime(2021, 5, 10), + new DateTime(2021, 5, 11), + new DateTime(2021, 5, 12), + new DateTime(2021, 5, 13), + new DateTime(2021, 5, 14) + }; Assert.Collection(sut1, dt => Assert.Equal("0:11:363:00:00:00.0", new DateSpan(sut0, dt).ToString()), @@ -345,5 +353,243 @@ public void Parse_ShouldGetTwelveMonthOfDifferenceWithinLeapYear_UsingIso8601Str TestOutput.WriteLine(span.ToString()); } + + [Fact] + public void Constructor_ShouldThrowArgumentNullExceptionWhenCalendarIsNull() + { + Assert.Throws(() => new DateSpan(DateTime.UtcNow, DateTime.UtcNow, null)); + } + + [Fact] + public void Constructor_WithSingleDate_ShouldUseTodayAsUpperBoundary() + { + var today = DateTime.Today; + var sut = new DateSpan(today); + var expected = new DateSpan(today, today); + + Assert.Equal(expected, sut); + Assert.Equal(0, sut.Years); + Assert.Equal(0, sut.Months); + Assert.Equal(0, sut.Days); + } + + [Fact] + public void Constructor_ShouldNormalizeReversedRange() + { + var earlier = new DateTime(2021, 3, 5); + var later = new DateTime(2021, 4, 5); + + var sut = new DateSpan(later, earlier); + var expected = new DateSpan(earlier, later); + + Assert.Equal(expected, sut); + Assert.True(sut == expected); + Assert.False(sut != expected); + } + + [Fact] + public void Constructor_ShouldAdjustYearWhenFullYearHasNotElapsed() + { + var sut = new DateSpan(new DateTime(2020, 3, 1), new DateTime(2021, 2, 28)); + + Assert.Equal(0, sut.Years); + Assert.Equal(11, sut.Months); + Assert.Equal(364, sut.Days); + } + + [Fact] + public void Constructor_ShouldCapturePartialMonthTimeDifference() + { + var sut = new DateSpan(new DateTime(2021, 1, 31, 23, 0, 0, 0), new DateTime(2021, 2, 1, 22, 0, 0, 500)); + + Assert.Equal(0, sut.Years); + Assert.Equal(0, sut.Months); + Assert.Equal(0, sut.Days); + Assert.Equal(23, sut.Hours); + Assert.Equal(0, sut.Minutes); + Assert.Equal(0, sut.Seconds); + Assert.Equal(500, sut.Milliseconds); + Assert.Equal(TimeSpan.FromHours(23).Add(TimeSpan.FromMilliseconds(500)).Ticks, sut.Ticks); + } + + [Fact] + public void Parse_WithSingleDate_ShouldUseTodayAsUpperBoundary() + { + var today = DateTime.Today; + var sut = DateSpan.Parse(today.ToString("s", CultureInfo.InvariantCulture)); + var expected = new DateSpan(today, today); + + Assert.Equal(expected, sut); + } + + [Fact] + public void Parse_WithCulture_ShouldUseProvidedCultureCalendar() + { + var culture = CultureInfo.InvariantCulture; + var start = new DateTime(2021, 3, 5).ToString("s", culture); + var end = new DateTime(2021, 4, 5).ToString("s", culture); + + var sut = DateSpan.Parse(start, end, culture); + var expected = new DateSpan(new DateTime(2021, 3, 5), new DateTime(2021, 4, 5), culture.Calendar); + + Assert.Equal(expected, sut); + } + + [Fact] + public void Equals_ShouldReturnFalseForNonDateSpanObject() + { + Assert.False(new DateSpan().Equals("DateSpan")); + } + + [Fact] + public void Equals_ShouldReturnFalseForDifferentCalendarTypes() + { + var start = new DateTime(2021, 3, 5); + var end = new DateTime(2021, 4, 5); + var left = new DateSpan(start, end, new GregorianCalendar()); + var right = new DateSpan(start, end, new JulianCalendar()); + + Assert.False(left.Equals(right)); + Assert.True(left != right); + } + + [Theory] + [InlineData(2021, 3, 1, 2021, 3, 3, 2)] + [InlineData(2021, 3, 5, 2021, 3, 7, 2)] + public void GetWeeks_ShouldHandleShortRanges(int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay, int expected) + { + var sut = new DateSpan(new DateTime(startYear, startMonth, startDay), new DateTime(endYear, endMonth, endDay)); + + Assert.Equal(expected, sut.GetWeeks()); + } + + [Theory] + [MemberData(nameof(GetSupportedCalendars))] + public void Constructor_ShouldSupportCalendarImplementations(DateTime start, DateTime end, Func calendarFactory) + { + var sut = new DateSpan(start, end, calendarFactory()); + var expected = new DateSpan(start, end, calendarFactory()); + + Assert.Equal(expected, sut); + Assert.Equal(1, sut.Days); + } + + public static IEnumerable GetSupportedCalendars() + { + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new ChineseLunisolarCalendar()) }; + yield return new object[] { new DateTime(31, 3, 5), new DateTime(31, 3, 6), (Func)(() => new JapaneseLunisolarCalendar()) }; + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new KoreanLunisolarCalendar()) }; + yield return new object[] { new DateTime(100, 3, 5), new DateTime(100, 3, 6), (Func)(() => new TaiwanLunisolarCalendar()) }; + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new GregorianCalendar()) }; + yield return new object[] { new DateTime(5343, 3, 5), new DateTime(5343, 3, 6), (Func)(() => new HebrewCalendar()) }; + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new HijriCalendar()) }; + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new JapaneseCalendar()) }; + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new JulianCalendar()) }; + yield return new object[] { new DateTime(2334, 3, 5), new DateTime(2334, 3, 6), (Func)(() => new KoreanCalendar()) }; + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new PersianCalendar()) }; + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new TaiwanCalendar()) }; + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new ThaiBuddhistCalendar()) }; + yield return new object[] { new DateTime(1400, 3, 5), new DateTime(1400, 3, 6), (Func)(() => new UmAlQuraCalendar()) }; + yield return new object[] { new DateTime(2021, 3, 5), new DateTime(2021, 3, 6), (Func)(() => new DelegatingCalendar()) }; + } + + private sealed class DelegatingCalendar : Calendar + { + private readonly GregorianCalendar _inner = new GregorianCalendar(); + + public override DateTime MinSupportedDateTime => _inner.MinSupportedDateTime; + + public override DateTime MaxSupportedDateTime => _inner.MaxSupportedDateTime; + + public override CalendarAlgorithmType AlgorithmType => _inner.AlgorithmType; + + public override int[] Eras => _inner.Eras; + + public override int TwoDigitYearMax + { + get => _inner.TwoDigitYearMax; + set => _inner.TwoDigitYearMax = value; + } + + public override DateTime AddMonths(DateTime time, int months) + { + return _inner.AddMonths(time, months); + } + + public override DateTime AddYears(DateTime time, int years) + { + return _inner.AddYears(time, years); + } + + public override int GetDayOfMonth(DateTime time) + { + return _inner.GetDayOfMonth(time); + } + + public override DayOfWeek GetDayOfWeek(DateTime time) + { + return _inner.GetDayOfWeek(time); + } + + public override int GetDayOfYear(DateTime time) + { + return _inner.GetDayOfYear(time); + } + + public override int GetDaysInMonth(int year, int month, int era) + { + return _inner.GetDaysInMonth(year, month, era); + } + + public override int GetDaysInYear(int year, int era) + { + return _inner.GetDaysInYear(year, era); + } + + public override int GetEra(DateTime time) + { + return _inner.GetEra(time); + } + + public override int GetMonth(DateTime time) + { + return _inner.GetMonth(time); + } + + public override int GetMonthsInYear(int year, int era) + { + return _inner.GetMonthsInYear(year, era); + } + + public override int GetYear(DateTime time) + { + return _inner.GetYear(time); + } + + public override bool IsLeapDay(int year, int month, int day, int era) + { + return _inner.IsLeapDay(year, month, day, era); + } + + public override bool IsLeapMonth(int year, int month, int era) + { + return _inner.IsLeapMonth(year, month, era); + } + + public override bool IsLeapYear(int year, int era) + { + return _inner.IsLeapYear(year, era); + } + + public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) + { + return _inner.ToDateTime(year, month, day, hour, minute, second, millisecond, era); + } + + public override int ToFourDigitYear(int year) + { + return _inner.ToFourDigitYear(year); + } + } } -} \ No newline at end of file +} diff --git a/test/Cuemon.Kernel.Tests/RangeTest.cs b/test/Cuemon.Kernel.Tests/RangeTest.cs new file mode 100644 index 000000000..42d22a6e0 --- /dev/null +++ b/test/Cuemon.Kernel.Tests/RangeTest.cs @@ -0,0 +1,104 @@ +using System; +using System.Globalization; +using Codebelt.Extensions.Xunit; +using Xunit; + +namespace Cuemon +{ + public class RangeTest : Test + { + public RangeTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void Equals_ShouldHandleReferenceAndNullCases() + { + var start = new DateTime(2021, 3, 5, 6, 7, 8); + var end = new DateTime(2021, 3, 6, 8, 10, 12); + var sut = new DateTimeRange(start, end); + + Assert.True(sut.Equals(sut, sut)); + Assert.False(sut.Equals(null, sut)); + Assert.False(sut.Equals(sut, null)); + } + + [Fact] + public void Equals_ShouldReturnFalseForDifferentDerivedTypes() + { + var start = new DateTime(2021, 3, 5, 6, 7, 8); + var end = new DateTime(2021, 3, 6, 8, 10, 12); + Range left = new DateTimeRange(start, end); + Range right = new DateTimeRangeStub(start, end); + + Assert.False(left.Equals(left, right)); + } + + [Fact] + public void Equals_ShouldCompareBoundaries() + { + var start = new DateTime(2021, 3, 5, 6, 7, 8); + var end = new DateTime(2021, 3, 6, 8, 10, 12); + var comparer = new DateTimeRange(start, end); + var left = new DateTimeRange(start, end); + var equal = new DateTimeRange(start, end); + var different = new DateTimeRange(start, end.AddSeconds(1)); + + Assert.True(comparer.Equals(left, equal)); + Assert.False(comparer.Equals(left, different)); + } + + [Fact] + public void GetHashCode_ShouldXorBoundaries() + { + var start = new DateTime(2021, 3, 5, 6, 7, 8); + var end = new DateTime(2021, 3, 6, 8, 10, 12); + var sut = new DateTimeRange(start, end); + + Assert.Equal(start.GetHashCode() ^ end.GetHashCode(), sut.GetHashCode(sut)); + } + + [Fact] + public void DateTimeRange_ShouldExposeDurationAndFormatUsingSortablePattern() + { + var start = new DateTime(2021, 3, 5, 6, 7, 8); + var end = new DateTime(2021, 3, 6, 8, 10, 12); + var sut = new DateTimeRange(start, end); + + Assert.Equal(start, sut.Start); + Assert.Equal(end, sut.End); + Assert.Equal(new TimeSpan(1, 2, 3, 4), sut.Duration); + Assert.Equal("A duration of 01.02:03:04 between 2021-03-05T06:07:08 and 2021-03-06T08:10:12.", sut.ToString("s", CultureInfo.InvariantCulture)); + Assert.Equal("A duration of 01.02:03:04 between 2021-03-05T06:07:08 and 2021-03-06T08:10:12.", sut.ToString()); + } + + [Fact] + public void TimeRange_ShouldUseDefaultDurationAndConstantPattern() + { + var start = new TimeSpan(6, 7, 8); + var end = new TimeSpan(8, 10, 12); + var sut = new TimeRange(start, end); + + Assert.Equal(start, sut.Start); + Assert.Equal(end, sut.End); + Assert.Equal(new TimeSpan(2, 3, 4), sut.Duration); + Assert.Equal("A duration of 00.02:03:04 between 06:07:08 and 08:10:12.", sut.ToString("c", CultureInfo.InvariantCulture)); + Assert.Equal("A duration of 00.02:03:04 between 06:07:08 and 08:10:12.", sut.ToString()); + } + + [Fact] + public void TimeRange_ShouldUseCustomDurationResolverWhenProvided() + { + var sut = new TimeRange(TimeSpan.FromHours(1), TimeSpan.FromHours(2), () => TimeSpan.FromHours(3)); + + Assert.Equal(TimeSpan.FromHours(3), sut.Duration); + } + + private sealed class DateTimeRangeStub : Range + { + public DateTimeRangeStub(DateTime start, DateTime end) : base(start, end, () => end.Subtract(start)) + { + } + } + } +} diff --git a/test/Cuemon.Runtime.Caching.Tests/Cuemon.Runtime.Caching.Tests.csproj b/test/Cuemon.Runtime.Caching.Tests/Cuemon.Runtime.Caching.Tests.csproj index 23f01c3eb..baacc78e0 100644 --- a/test/Cuemon.Runtime.Caching.Tests/Cuemon.Runtime.Caching.Tests.csproj +++ b/test/Cuemon.Runtime.Caching.Tests/Cuemon.Runtime.Caching.Tests.csproj @@ -2,7 +2,7 @@ - net10.0;net9.0 + net11.0;net10.0 Cuemon.Runtime.Caching diff --git a/test/Cuemon.Security.Cryptography.Tests/UnkeyedHashFactoryTest.cs b/test/Cuemon.Security.Cryptography.Tests/UnkeyedHashFactoryTest.cs index 9fc57fc18..743cc4cbf 100644 --- a/test/Cuemon.Security.Cryptography.Tests/UnkeyedHashFactoryTest.cs +++ b/test/Cuemon.Security.Cryptography.Tests/UnkeyedHashFactoryTest.cs @@ -45,7 +45,7 @@ public void CreateCryptoSha256_ShouldBeValidHashResult() Assert.Equal("db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0", h.ComputeHash(Alphanumeric.LettersAndNumbers).ToHexadecimalString()); Assert.Equal("db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0", h.ComputeHash(Decorator.Enclose(Alphanumeric.LettersAndNumbers).ToStream()).ToHexadecimalString()); Assert.Equal("84d89877f0d4041efb6bf91a16f0248f2fd573e6af05c19f96bedb9f882f7882", h.ComputeHash(Alphanumeric.Numbers).ToHexadecimalString()); -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER Assert.Equal("53ab3a50f51855beeae9721ab68656312c7f105b9b34bbfa97875dbfda72dbc6", h.ComputeHash(DateTime.UnixEpoch).ToHexadecimalString()); #endif Assert.Equal("1f1a24c833be74a0f4f99007aa70a51e2456e41f745a5628721ea2b8e1c07641", h.ComputeHash(213, "fdfsfsf", 9999).ToHexadecimalString()); diff --git a/testenvironments.json b/testenvironments.json index e49a8cd13..7129ca1a8 100644 --- a/testenvironments.json +++ b/testenvironments.json @@ -1,20 +1,20 @@ { - "version": "1", - "environments": [ - { - "name": "WSL-Ubuntu", - "type": "wsl", - "wslDistribution": "Ubuntu-24.04" - }, - { - "name": "Docker-Ubuntu (net9)", - "type": "docker", - "dockerImage": "codebeltnet/ubuntu-testrunner:9" - }, - { - "name": "Docker-Ubuntu (net10)", - "type": "docker", - "dockerImage": "codebeltnet/ubuntu-testrunner:10" - } - ] + "version": "1", + "environments": [ + { + "name": "WSL-Ubuntu", + "type": "wsl", + "wslDistribution": "Ubuntu-24.04" + }, + { + "name": "Docker-Ubuntu (net10)", + "type": "docker", + "dockerImage": "codebeltnet/ubuntu-testrunner:10" + }, + { + "name": "Docker-Ubuntu (net11)", + "type": "docker", + "dockerImage": "codebeltnet/ubuntu-testrunner:11" + } + ] }