diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index 75ee5a8a27d37a..8c7fedd7fcd626 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -50,6 +50,7 @@ public static partial class PlatformDetection public static bool IsSolaris => RuntimeInformation.IsOSPlatform(OSPlatform.Create("SOLARIS")); public static bool IsBrowser => RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")); public static bool IsWasi => RuntimeInformation.IsOSPlatform(OSPlatform.Create("WASI")); + public static bool IsWasm => IsBrowser || IsWasi; public static bool IsNotBrowser => !IsBrowser; public static bool IsNotWasi => !IsWasi; public static bool IsMobile => IsBrowser || IsWasi || IsAppleMobile || IsAndroid; diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Icu.cs index 8c91464a9d86c3..bc6ad25073b985 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Icu.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Icu.cs @@ -15,11 +15,11 @@ private static unsafe bool IcuIsNormalized(ReadOnlySpan source, Normalizat Debug.Assert(!GlobalizationMode.Invariant); Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(!source.IsEmpty); -#pragma warning disable CA1416 // FormKC and FormKD are unsupported on browser, ValidateArguments is throwing PlatformNotSupportedException in that case so suppressing the warning here +#pragma warning disable CA1416 // FormKC and FormKD are unsupported on browser, CheckNormalizationForm is throwing PlatformNotSupportedException in that case so suppressing the warning here Debug.Assert(normalizationForm is NormalizationForm.FormC or NormalizationForm.FormD or NormalizationForm.FormKC or NormalizationForm.FormKD); #pragma warning restore CA1416 - ValidateArguments(source, normalizationForm, nameof(source)); + ValidateArguments(source, nameof(source)); int ret; fixed (char* pInput = source) @@ -50,7 +50,7 @@ private static unsafe string IcuNormalize(string strInput, NormalizationForm nor Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(normalizationForm == NormalizationForm.FormC || normalizationForm == NormalizationForm.FormD || normalizationForm == NormalizationForm.FormKC || normalizationForm == NormalizationForm.FormKD); - ValidateArguments(strInput, normalizationForm); + ValidateArguments(strInput); char[]? toReturn = null; try @@ -132,7 +132,7 @@ private static unsafe bool IcuTryNormalize(ReadOnlySpan source, Span return false; } - ValidateArguments(source, normalizationForm, nameof(source)); + ValidateArguments(source, nameof(source)); int realLen; fixed (char* pInput = source) @@ -172,7 +172,7 @@ private static unsafe int IcuGetNormalizedLength(ReadOnlySpan source, Norm Debug.Assert(!source.IsEmpty); Debug.Assert(normalizationForm == NormalizationForm.FormC || normalizationForm == NormalizationForm.FormD || normalizationForm == NormalizationForm.FormKC || normalizationForm == NormalizationForm.FormKD); - ValidateArguments(source, normalizationForm, nameof(source)); + ValidateArguments(source, nameof(source)); int realLen; fixed (char* pInput = source) @@ -197,14 +197,8 @@ private static unsafe int IcuGetNormalizedLength(ReadOnlySpan source, Norm return realLen; } - private static void ValidateArguments(ReadOnlySpan strInput, NormalizationForm normalizationForm, string paramName = "strInput") + private static void ValidateArguments(ReadOnlySpan strInput, string paramName = "strInput") { - if ((OperatingSystem.IsBrowser() || OperatingSystem.IsWasi()) && (normalizationForm == NormalizationForm.FormKC || normalizationForm == NormalizationForm.FormKD)) - { - // Browser's ICU doesn't contain data needed for FormKC and FormKD - throw new PlatformNotSupportedException(SR.Argument_UnsupportedNormalizationFormInBrowser); - } - if (HasInvalidUnicodeSequence(strInput)) { throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, paramName); diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.cs index 0668940b1365ea..2f588b614c350b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.cs @@ -94,6 +94,15 @@ private static void CheckNormalizationForm(NormalizationForm normalizationForm) { throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); } + + if ((OperatingSystem.IsBrowser() || OperatingSystem.IsWasi()) && + !GlobalizationMode.Invariant && + !GlobalizationMode.UseNls && + (normalizationForm == NormalizationForm.FormKC || normalizationForm == NormalizationForm.FormKD)) + { + // Browser/WASI builds ship without compatibility normalization data. + throw new PlatformNotSupportedException(SR.Argument_UnsupportedNormalizationFormInBrowser); + } } } } diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Extensions.Tests/Normalization/StringNormalizationTests.cs b/src/libraries/System.Runtime/tests/System.Globalization.Extensions.Tests/Normalization/StringNormalizationTests.cs index d2b35b018a3fac..db01ff01df39d5 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Extensions.Tests/Normalization/StringNormalizationTests.cs +++ b/src/libraries/System.Runtime/tests/System.Globalization.Extensions.Tests/Normalization/StringNormalizationTests.cs @@ -138,5 +138,29 @@ public void Normalize_Null() { AssertExtensions.Throws("strInput", () => StringNormalizationExtensions.Normalize(null)); } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWasm))] + public void NormalizationForms_ThrowOnNotSupportedPlatforms() + { + AssertNormalizationFormThrows(NormalizationForm.FormKC); + AssertNormalizationFormThrows(NormalizationForm.FormKD); + } + + private static void AssertNormalizationFormThrows(NormalizationForm normalizationForm) + { + foreach (string value in new[] { "ascii", "😊" }) + { + Assert.Throws(() => value.IsNormalized(normalizationForm)); + Assert.Throws(() => value.AsSpan().IsNormalized(normalizationForm)); + Assert.Throws(() => value.Normalize(normalizationForm)); + + Assert.Throws(() => + { + Span destination = stackalloc char[32]; + value.AsSpan().TryNormalize(destination, out _, normalizationForm); + }); + Assert.Throws(() => value.AsSpan().GetNormalizedLength(normalizationForm)); + } + } } }