diff --git a/.docfx/Dockerfile.docfx b/.docfx/Dockerfile.docfx index 04c49b3..9d42262 100644 --- a/.docfx/Dockerfile.docfx +++ b/.docfx/Dockerfile.docfx @@ -1,4 +1,4 @@ -ARG NGINX_VERSION=1.30.0-alpine +ARG NGINX_VERSION=1.31.0-alpine FROM --platform=$BUILDPLATFORM nginx:${NGINX_VERSION} AS base RUN rm -rf /usr/share/nginx/html/* diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 616f6b5..a55efa9 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -139,7 +139,7 @@ jobs: if: github.event_name != 'pull_request' name: call-nuget needs: [build, pack, test_linux, test_windows, sonarcloud, codecov, codeql] - uses: codebeltnet/jobs-nuget-push/.github/workflows/default.yml@v2 + uses: codebeltnet/jobs-nuget-push/.github/workflows/default.yml@v3 with: version: ${{ needs.build.outputs.version }} environment: Production diff --git a/.nuget/Codebelt.Extensions.Globalization/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Globalization/PackageReleaseNotes.txt index 42c80f1..9aca67d 100644 --- a/.nuget/Codebelt.Extensions.Globalization/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Globalization/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.0.7 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.0.6 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 368e7f7..e8181c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ For more details, please refer to `PackageReleaseNotes.txt` on a per assembly ba > [!NOTE] > Changelog entries prior to version 9.0.1 was migrated from previous versions of Cuemon.Extensions.Globalization. +## [10.0.7] - 2026-05-23 + +This is a service update that focuses on package dependencies. + ## [10.0.6] - 2026-04-18 This is a service update that focuses on package dependencies. diff --git a/Directory.Packages.props b/Directory.Packages.props index d9466ea..d42dfff 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,12 +3,12 @@ true - - - + + + - - + + diff --git a/test/Codebelt.Extensions.Globalization.Tests/CultureInfoExtensionsTest.cs b/test/Codebelt.Extensions.Globalization.Tests/CultureInfoExtensionsTest.cs index 2664ba1..84118eb 100644 --- a/test/Codebelt.Extensions.Globalization.Tests/CultureInfoExtensionsTest.cs +++ b/test/Codebelt.Extensions.Globalization.Tests/CultureInfoExtensionsTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Runtime.InteropServices; using Codebelt.Extensions.Xunit; using Xunit; @@ -13,6 +14,36 @@ public CultureInfoExtensionsTest(ITestOutputHelper output) : base(output) { } + [Fact] + public void UseNationalLanguageSupport_ShouldCloneAndEnrich_WhenCultureInfoIsReadOnly() + { + var sut = CultureInfo.GetCultureInfo("fr-FR").UseNationalLanguageSupport(); + + Assert.NotNull(sut); + Assert.NotNull(sut.DateTimeFormat); + Assert.NotNull(sut.NumberFormat); + + TestOutput.WriteLine($"{sut.EnglishName}: ShortDatePattern={sut.DateTimeFormat.ShortDatePattern}"); + } + + [Fact] + public void UseNationalLanguageSupport_ShouldThrowInvalidOperationException_WhenNoSurrogateExists() + { + Assert.Throws(() => new CultureInfo("en").UseNationalLanguageSupport()); + } + + [Fact] + public void UseNationalLanguageSupport_ShouldThrowArgumentNullException_WhenCultureIsNull() + { + Assert.Throws(() => ((CultureInfo)null).UseNationalLanguageSupport()); + } + + [Fact] + public void UseNationalLanguageSupport_ShouldThrowArgumentNullException_WhenCulturesIsNull() + { + Assert.Throws(() => ((IEnumerable)null).UseNationalLanguageSupport().ToList()); + } + [Fact] public void UseNationalLanguageSupport_ShouldHaveDifferentFormattingAsWindowsVariant() { diff --git a/test/Codebelt.Extensions.Globalization.Tests/CultureInfoSurrogateTest.cs b/test/Codebelt.Extensions.Globalization.Tests/CultureInfoSurrogateTest.cs new file mode 100644 index 0000000..e36ca6c --- /dev/null +++ b/test/Codebelt.Extensions.Globalization.Tests/CultureInfoSurrogateTest.cs @@ -0,0 +1,42 @@ +using System.Reflection; +using Codebelt.Extensions.Xunit; +using Xunit; + +namespace Codebelt.Extensions.Globalization +{ + public class CultureInfoSurrogateTest : Test + { + public CultureInfoSurrogateTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void Constructor_ShouldAssignDateTimeAndNumberFormats_WhenSurrogatesAreProvided() + { + var assembly = typeof(CultureInfoExtensions).Assembly; + var cultureInfoSurrogateType = assembly.GetType("Codebelt.Extensions.Globalization.CultureInfoSurrogate"); + var dtfiSurrogateType = assembly.GetType("Codebelt.Extensions.Globalization.DateTimeFormatInfoSurrogate"); + var nfiSurrogateType = assembly.GetType("Codebelt.Extensions.Globalization.NumberFormatInfoSurrogate"); + + var dtSurrogate = System.Activator.CreateInstance(dtfiSurrogateType, nonPublic: true); + var nfSurrogate = System.Activator.CreateInstance(nfiSurrogateType, nonPublic: true); + + var ctor = cultureInfoSurrogateType.GetConstructor( + BindingFlags.Instance | BindingFlags.NonPublic, + null, + new[] { dtfiSurrogateType, nfiSurrogateType }, + null); + + var sut = ctor.Invoke(new[] { dtSurrogate, nfSurrogate }); + + var dateTimeFormatProp = cultureInfoSurrogateType.GetProperty("DateTimeFormat", BindingFlags.Instance | BindingFlags.NonPublic); + var numberFormatProp = cultureInfoSurrogateType.GetProperty("NumberFormat", BindingFlags.Instance | BindingFlags.NonPublic); + + Assert.Same(dtSurrogate, dateTimeFormatProp.GetValue(sut)); + Assert.Same(nfSurrogate, numberFormatProp.GetValue(sut)); + + TestOutput.WriteLine($"DateTimeFormat assigned: {dateTimeFormatProp.GetValue(sut) != null}"); + TestOutput.WriteLine($"NumberFormat assigned: {numberFormatProp.GetValue(sut) != null}"); + } + } +} diff --git a/test/Codebelt.Extensions.Globalization.Tests/DateTimeFormatInfoSurrogateTest.cs b/test/Codebelt.Extensions.Globalization.Tests/DateTimeFormatInfoSurrogateTest.cs new file mode 100644 index 0000000..b85b36f --- /dev/null +++ b/test/Codebelt.Extensions.Globalization.Tests/DateTimeFormatInfoSurrogateTest.cs @@ -0,0 +1,50 @@ +using System; +using System.Globalization; +using System.Reflection; +using Codebelt.Extensions.Xunit; +using Xunit; + +namespace Codebelt.Extensions.Globalization +{ + public class DateTimeFormatInfoSurrogateTest : Test + { + public DateTimeFormatInfoSurrogateTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void Constructor_ShouldCopyAllPropertiesFromDateTimeFormatInfo_WhenDateTimeFormatInfoIsProvided() + { + var assembly = typeof(CultureInfoExtensions).Assembly; + var type = assembly.GetType("Codebelt.Extensions.Globalization.DateTimeFormatInfoSurrogate"); + var ctor = type.GetConstructor( + BindingFlags.Instance | BindingFlags.NonPublic, + null, + new[] { typeof(DateTimeFormatInfo) }, + null); + + var dtfi = new CultureInfo("da-DK", false).DateTimeFormat; + var sut = ctor.Invoke(new object[] { dtfi }); + + Assert.Equal(dtfi.AMDesignator, (string)type.GetProperty("AMDesignator").GetValue(sut)); + Assert.Equal(dtfi.CalendarWeekRule, (CalendarWeekRule)type.GetProperty("CalendarWeekRule").GetValue(sut)); + Assert.Equal(dtfi.DateSeparator, (string)type.GetProperty("DateSeparator").GetValue(sut)); + Assert.Equal(dtfi.FirstDayOfWeek, (DayOfWeek)type.GetProperty("FirstDayOfWeek").GetValue(sut)); + Assert.Equal(dtfi.FullDateTimePattern, (string)type.GetProperty("FullDateTimePattern").GetValue(sut)); + Assert.Equal(dtfi.LongDatePattern, (string)type.GetProperty("LongDatePattern").GetValue(sut)); + Assert.Equal(dtfi.LongTimePattern, (string)type.GetProperty("LongTimePattern").GetValue(sut)); + Assert.Equal(dtfi.MonthDayPattern, (string)type.GetProperty("MonthDayPattern").GetValue(sut)); + Assert.Equal(dtfi.PMDesignator, (string)type.GetProperty("PMDesignator").GetValue(sut)); + Assert.Equal(dtfi.ShortDatePattern, (string)type.GetProperty("ShortDatePattern").GetValue(sut)); + Assert.Equal(dtfi.ShortTimePattern, (string)type.GetProperty("ShortTimePattern").GetValue(sut)); + Assert.Equal(dtfi.TimeSeparator, (string)type.GetProperty("TimeSeparator").GetValue(sut)); + Assert.Equal(dtfi.YearMonthPattern, (string)type.GetProperty("YearMonthPattern").GetValue(sut)); + Assert.Equal(dtfi.ShortestDayNames, (string[])type.GetProperty("ShortestDayNames").GetValue(sut)); + Assert.Equal(dtfi.AbbreviatedDayNames, (string[])type.GetProperty("AbbreviatedDayNames").GetValue(sut)); + Assert.Equal(dtfi.AbbreviatedMonthNames, (string[])type.GetProperty("AbbreviatedMonthNames").GetValue(sut)); + Assert.Equal(dtfi.AbbreviatedMonthGenitiveNames, (string[])type.GetProperty("AbbreviatedMonthGenitiveNames").GetValue(sut)); + + TestOutput.WriteLine($"ShortDatePattern: {(string)type.GetProperty("ShortDatePattern").GetValue(sut)}"); + } + } +} diff --git a/test/Codebelt.Extensions.Globalization.Tests/NumberFormatInfoSurrogateTest.cs b/test/Codebelt.Extensions.Globalization.Tests/NumberFormatInfoSurrogateTest.cs new file mode 100644 index 0000000..1843048 --- /dev/null +++ b/test/Codebelt.Extensions.Globalization.Tests/NumberFormatInfoSurrogateTest.cs @@ -0,0 +1,55 @@ +using System.Globalization; +using System.Reflection; +using Codebelt.Extensions.Xunit; +using Xunit; + +namespace Codebelt.Extensions.Globalization +{ + public class NumberFormatInfoSurrogateTest : Test + { + public NumberFormatInfoSurrogateTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void Constructor_ShouldCopyAllPropertiesFromNumberFormatInfo_WhenNumberFormatInfoIsProvided() + { + var assembly = typeof(CultureInfoExtensions).Assembly; + var type = assembly.GetType("Codebelt.Extensions.Globalization.NumberFormatInfoSurrogate"); + var ctor = type.GetConstructor( + BindingFlags.Instance | BindingFlags.NonPublic, + null, + new[] { typeof(NumberFormatInfo) }, + null); + + var nfi = new CultureInfo("da-DK", false).NumberFormat; + var sut = ctor.Invoke(new object[] { nfi }); + + Assert.Equal(nfi.CurrencyDecimalDigits, (int)type.GetProperty("CurrencyDecimalDigits").GetValue(sut)); + Assert.Equal(nfi.CurrencyDecimalSeparator, (string)type.GetProperty("CurrencyDecimalSeparator").GetValue(sut)); + Assert.Equal(nfi.CurrencyGroupSeparator, (string)type.GetProperty("CurrencyGroupSeparator").GetValue(sut)); + Assert.Equal(nfi.CurrencyNegativePattern, (int)type.GetProperty("CurrencyNegativePattern").GetValue(sut)); + Assert.Equal(nfi.CurrencyPositivePattern, (int)type.GetProperty("CurrencyPositivePattern").GetValue(sut)); + Assert.Equal(nfi.CurrencySymbol, (string)type.GetProperty("CurrencySymbol").GetValue(sut)); + Assert.Equal(nfi.DigitSubstitution, (DigitShapes)type.GetProperty("DigitSubstitution").GetValue(sut)); + Assert.Equal(nfi.NaNSymbol, (string)type.GetProperty("NaNSymbol").GetValue(sut)); + Assert.Equal(nfi.NegativeInfinitySymbol, (string)type.GetProperty("NegativeInfinitySymbol").GetValue(sut)); + Assert.Equal(nfi.NegativeSign, (string)type.GetProperty("NegativeSign").GetValue(sut)); + Assert.Equal(nfi.NumberDecimalDigits, (int)type.GetProperty("NumberDecimalDigits").GetValue(sut)); + Assert.Equal(nfi.NumberDecimalSeparator, (string)type.GetProperty("NumberDecimalSeparator").GetValue(sut)); + Assert.Equal(nfi.NumberGroupSeparator, (string)type.GetProperty("NumberGroupSeparator").GetValue(sut)); + Assert.Equal(nfi.NumberNegativePattern, (int)type.GetProperty("NumberNegativePattern").GetValue(sut)); + Assert.Equal(nfi.PerMilleSymbol, (string)type.GetProperty("PerMilleSymbol").GetValue(sut)); + Assert.Equal(nfi.PercentDecimalDigits, (int)type.GetProperty("PercentDecimalDigits").GetValue(sut)); + Assert.Equal(nfi.PercentDecimalSeparator, (string)type.GetProperty("PercentDecimalSeparator").GetValue(sut)); + Assert.Equal(nfi.PercentGroupSeparator, (string)type.GetProperty("PercentGroupSeparator").GetValue(sut)); + Assert.Equal(nfi.PercentNegativePattern, (int)type.GetProperty("PercentNegativePattern").GetValue(sut)); + Assert.Equal(nfi.PercentPositivePattern, (int)type.GetProperty("PercentPositivePattern").GetValue(sut)); + Assert.Equal(nfi.PercentSymbol, (string)type.GetProperty("PercentSymbol").GetValue(sut)); + Assert.Equal(nfi.PositiveInfinitySymbol, (string)type.GetProperty("PositiveInfinitySymbol").GetValue(sut)); + Assert.Equal(nfi.PositiveSign, (string)type.GetProperty("PositiveSign").GetValue(sut)); + + TestOutput.WriteLine($"CurrencySymbol: {(string)type.GetProperty("CurrencySymbol").GetValue(sut)}"); + } + } +}