From 9d1c4af7f972c0d48fdb86e04b3c33a1baa3e6a7 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan Date: Tue, 24 Sep 2024 12:21:38 +0200 Subject: [PATCH 1/4] Enable and disable tests for hybrid globalization on Apple --- .../Common/tests/Tests/System/StringTests.cs | 66 ++++++++++--------- .../Data/SqlTypes/SqlStringSortingTest.cs | 3 +- .../GetStringComparerTests.cs | 3 +- .../CompareInfo/CompareInfoTests.HashCode.cs | 3 +- .../AssemblyNameTests.cs | 3 +- .../System/DateTimeTests.cs | 4 +- .../System/Text/RuneTests.cs | 4 +- 7 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/libraries/Common/tests/Tests/System/StringTests.cs b/src/libraries/Common/tests/Tests/System/StringTests.cs index b756c06d87d6f6..359267c1c6fc20 100644 --- a/src/libraries/Common/tests/Tests/System/StringTests.cs +++ b/src/libraries/Common/tests/Tests/System/StringTests.cs @@ -1011,7 +1011,6 @@ public static void MakeSureNoCompareToChecksGoOutOfRange_StringComparison() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] public static void CompareToNoMatch_StringComparison() { for (int length = 1; length < 150; length++) @@ -1037,22 +1036,25 @@ public static void CompareToNoMatch_StringComparison() // Due to differences in the implementation, the exact result of CompareTo will not necessarily match with string.Compare. // However, the sign will match, which is what defines correctness. - Assert.Equal( - Math.Sign(string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.OrdinalIgnoreCase)), - Math.Sign(firstSpan.CompareTo(secondSpan, StringComparison.OrdinalIgnoreCase))); - - Assert.Equal( - string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.CurrentCulture), - firstSpan.CompareTo(secondSpan, StringComparison.CurrentCulture)); - Assert.Equal( - string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.CurrentCultureIgnoreCase), - firstSpan.CompareTo(secondSpan, StringComparison.CurrentCultureIgnoreCase)); - Assert.Equal( - string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.InvariantCulture), - firstSpan.CompareTo(secondSpan, StringComparison.InvariantCulture)); - Assert.Equal( - string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.InvariantCultureIgnoreCase), - firstSpan.CompareTo(secondSpan, StringComparison.InvariantCultureIgnoreCase)); + if (PlatformDetection.IsNotHybridGlobalizationOnApplePlatform) + { + Assert.Equal( + Math.Sign(string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.OrdinalIgnoreCase)), + Math.Sign(firstSpan.CompareTo(secondSpan, StringComparison.OrdinalIgnoreCase))); + + Assert.Equal( + string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.CurrentCulture), + firstSpan.CompareTo(secondSpan, StringComparison.CurrentCulture)); + Assert.Equal( + string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.CurrentCultureIgnoreCase), + firstSpan.CompareTo(secondSpan, StringComparison.CurrentCultureIgnoreCase)); + Assert.Equal( + string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.InvariantCulture), + firstSpan.CompareTo(secondSpan, StringComparison.InvariantCulture)); + Assert.Equal( + string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.InvariantCultureIgnoreCase), + firstSpan.CompareTo(secondSpan, StringComparison.InvariantCultureIgnoreCase)); + } } } } @@ -1286,7 +1288,6 @@ public static void ContainsMatchDifferentSpans_StringComparison() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] public static void ContainsNoMatch_StringComparison() { for (int length = 1; length < 150; length++) @@ -1313,18 +1314,21 @@ public static void ContainsNoMatch_StringComparison() Assert.False(firstSpan.Contains(secondSpan, StringComparison.OrdinalIgnoreCase)); // Different behavior depending on OS - Assert.Equal( - firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.CurrentCulture), - firstSpan.Contains(secondSpan, StringComparison.CurrentCulture)); - Assert.Equal( - firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.CurrentCultureIgnoreCase), - firstSpan.Contains(secondSpan, StringComparison.CurrentCultureIgnoreCase)); - Assert.Equal( - firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.InvariantCulture), - firstSpan.Contains(secondSpan, StringComparison.InvariantCulture)); - Assert.Equal( - firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.InvariantCultureIgnoreCase), - firstSpan.Contains(secondSpan, StringComparison.InvariantCultureIgnoreCase)); + if (PlatformDetection.IsNotHybridGlobalizationOnApplePlatform) + { + Assert.Equal( + firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.CurrentCulture), + firstSpan.Contains(secondSpan, StringComparison.CurrentCulture)); + Assert.Equal( + firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.CurrentCultureIgnoreCase), + firstSpan.Contains(secondSpan, StringComparison.CurrentCultureIgnoreCase)); + Assert.Equal( + firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.InvariantCulture), + firstSpan.Contains(secondSpan, StringComparison.InvariantCulture)); + Assert.Equal( + firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.InvariantCultureIgnoreCase), + firstSpan.Contains(secondSpan, StringComparison.InvariantCultureIgnoreCase)); + } } } } @@ -2113,7 +2117,6 @@ public static void EndsWithMatchDifferentSpans_StringComparison() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] public static void EndsWithNoMatch_StringComparison() { for (int length = 1; length < 150; length++) @@ -7379,7 +7382,6 @@ public static void StartsWithMatchDifferentSpans_StringComparison() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] public static void StartsWithNoMatch_StringComparison() { for (int length = 1; length < 150; length++) diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs index 7fa294f8fe95d4..f3d2712faa1127 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs @@ -37,8 +37,7 @@ public static class SqlStringSortingTest private static readonly UnicodeEncoding s_unicodeEncoding = new UnicodeEncoding(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: true); - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization), nameof(PlatformDetection.IsNotHybridGlobalizationOnApplePlatform))] [InlineData("ja-JP", 0x0411)] // Japanese - Japan [InlineData("ar-SA", 0x0401)] // Arabic - Saudi Arabia [InlineData("de-DE", 0x0407)] // German - Germany diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Extensions.Tests/GetStringComparerTests.cs b/src/libraries/System.Runtime/tests/System.Globalization.Extensions.Tests/GetStringComparerTests.cs index 3046f50a98c3e9..0735620db91af1 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Extensions.Tests/GetStringComparerTests.cs +++ b/src/libraries/System.Runtime/tests/System.Globalization.Extensions.Tests/GetStringComparerTests.cs @@ -19,8 +19,7 @@ public void GetStringComparer_Invalid() AssertExtensions.Throws("options", () => new CultureInfo("tr-TR").CompareInfo.GetStringComparer(CompareOptions.OrdinalIgnoreCase | CompareOptions.IgnoreCase)); } - [Theory] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotHybridGlobalizationOnApplePlatform))] [InlineData("hello", "hello", "fr-FR", CompareOptions.IgnoreCase, 0, 0)] [InlineData("hello", "HELLo", "fr-FR", CompareOptions.IgnoreCase, 0, 0)] [InlineData("hello", null, "fr-FR", CompareOptions.IgnoreCase, 1, 1)] diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.HashCode.cs b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.HashCode.cs index e05bcbf453e91f..b915c8855f4661 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.HashCode.cs +++ b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.HashCode.cs @@ -14,8 +14,7 @@ public class CompareInfoHashCodeTests : CompareInfoTestsBase { [OuterLoop] - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization), nameof(PlatformDetection.IsNotHybridGlobalizationOnApplePlatform))] public void CheckHashingInLineWithEqual() { int additionalCollisions = 0; diff --git a/src/libraries/System.Runtime/tests/System.Reflection.Tests/AssemblyNameTests.cs b/src/libraries/System.Runtime/tests/System.Reflection.Tests/AssemblyNameTests.cs index 873d3d474545a4..f5225adc18b783 100644 --- a/src/libraries/System.Runtime/tests/System.Reflection.Tests/AssemblyNameTests.cs +++ b/src/libraries/System.Runtime/tests/System.Reflection.Tests/AssemblyNameTests.cs @@ -221,8 +221,7 @@ public void CultureName_Set(AssemblyName assemblyName, string originalCultureNam Assert.Equal(new AssemblyName(expectedEqualString).FullName, assemblyName.FullName); } - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotHybridGlobalizationOnApplePlatform))] public void CultureName_Set_Invalid_ThrowsCultureNotFoundException() { var assemblyName = new AssemblyName("Test"); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs index 554d128a15933d..a9936fce7ffdf4 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs @@ -1982,7 +1982,7 @@ public static IEnumerable Parse_ValidInput_Succeeds_MemberData() yield return new object[] { "#2020-5-7T09:37:00.0000000+00:00#\0", CultureInfo.InvariantCulture, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(2020, 5, 7, 9, 37, 0, DateTimeKind.Utc), TimeZoneInfo.Local) }; yield return new object[] { "2020-5-7T09:37:00.0000000+00:00", CultureInfo.InvariantCulture, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(2020, 5, 7, 9, 37, 0, DateTimeKind.Utc), TimeZoneInfo.Local) }; - if (PlatformDetection.IsNotInvariantGlobalization) + if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnApplePlatform) { DateTime today = DateTime.Today; var hebrewCulture = new CultureInfo("he-IL"); @@ -2003,7 +2003,6 @@ public static IEnumerable Parse_ValidInput_Succeeds_MemberData() } [Theory] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] [MemberData(nameof(Parse_ValidInput_Succeeds_MemberData))] public static void Parse_ValidInput_Succeeds(string input, CultureInfo culture, DateTime? expected) { @@ -2464,7 +2463,6 @@ public static IEnumerable ToString_MatchesExpected_MemberData() } [Theory] - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] [MemberData(nameof(Parse_ValidInput_Succeeds_MemberData))] public static void Parse_Span_ValidInput_Succeeds(string input, CultureInfo culture, DateTime? expected) { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/RuneTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/RuneTests.cs index f7e20fbfe89384..c8a34beb9327b2 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/RuneTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/RuneTests.cs @@ -57,7 +57,8 @@ public static void Casing_Invariant(int original, int upper, int lower) Assert.Equal(new Rune(lower), Rune.ToLowerInvariant(rune)); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalizationAndNotHybridOnBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalizationAndNotHybridOnBrowser), PlatformDetection.IsNotHybridGlobalizationOnApplePlatform)] + // HybridGlobalization on Apple mobile platforms has issues with casing dotless I // HybridGlobalization on Browser uses Invariant HashCode and SortKey, so its effect does not match this of ICU [InlineData('0', '0', '0')] [InlineData('a', 'A', 'a')] @@ -71,7 +72,6 @@ public static void Casing_Invariant(int original, int upper, int lower) [InlineData('\u0131', '\u0131', '\u0131')] // U+0131 LATIN SMALL LETTER DOTLESS I [InlineData(0x10400, 0x10400, 0x10428)] // U+10400 DESERET CAPITAL LETTER LONG I [InlineData(0x10428, 0x10400, 0x10428)] // U+10428 DESERET SMALL LETTER LONG I - [ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnApplePlatform))] public static void ICU_Casing_Invariant(int original, int upper, int lower) { var rune = new Rune(original); From 50f5e7a029e5bd92d6fdd1806fa28f2d76328867 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan Date: Tue, 24 Sep 2024 15:54:55 +0200 Subject: [PATCH 2/4] fix build failure --- .../tests/System.Runtime.Tests/System/Text/RuneTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/RuneTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/RuneTests.cs index c8a34beb9327b2..578d09f3eaad69 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/RuneTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/RuneTests.cs @@ -57,7 +57,7 @@ public static void Casing_Invariant(int original, int upper, int lower) Assert.Equal(new Rune(lower), Rune.ToLowerInvariant(rune)); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalizationAndNotHybridOnBrowser), PlatformDetection.IsNotHybridGlobalizationOnApplePlatform)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalizationAndNotHybridOnBrowser), nameof(PlatformDetection.IsNotHybridGlobalizationOnApplePlatform))] // HybridGlobalization on Apple mobile platforms has issues with casing dotless I // HybridGlobalization on Browser uses Invariant HashCode and SortKey, so its effect does not match this of ICU [InlineData('0', '0', '0')] From 22cbfa637287a1e2b59fad0d7fd0b20377c33f0f Mon Sep 17 00:00:00 2001 From: Meri Khamoyan Date: Thu, 26 Sep 2024 17:32:23 +0200 Subject: [PATCH 3/4] Add comments --- docs/design/features/globalization-hybrid-mode.md | 5 +++++ src/libraries/Common/tests/Tests/System/StringTests.cs | 10 +++++++--- .../tests/System/Data/SqlTypes/SqlStringSortingTest.cs | 2 ++ .../CompareInfo/CompareInfoTests.HashCode.cs | 2 ++ .../tests/System.Runtime.Tests/System/DateTimeTests.cs | 3 +++ 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/design/features/globalization-hybrid-mode.md b/docs/design/features/globalization-hybrid-mode.md index bdbdb27b09e425..9e5b7ec7da5ccd 100644 --- a/docs/design/features/globalization-hybrid-mode.md +++ b/docs/design/features/globalization-hybrid-mode.md @@ -398,6 +398,11 @@ Affected public APIs: - String.Compare, - String.Equals. +Mapped to Apple Native API `compare:options:range:locale:`(https://developer.apple.com/documentation/foundation/nsstring/1414561-compare?language=objc)// This implementation uses normalization techniques such as `precomposedStringWithCanonicalMapping`, which can result in +behavior differences compared to other platforms. +Specifically, the use of precomposed strings and additional locale-based string folding can affect the results of comparisons. +Due to these differences, the exact result of string compariso on Apple platforms may differ. + The number of `CompareOptions` and `NSStringCompareOptions` combinations are limited. Originally supported combinations can be found [here for CompareOptions](https://learn.microsoft.com/dotnet/api/system.globalization.compareoptions) and [here for NSStringCompareOptions](https://developer.apple.com/documentation/foundation/nsstringcompareoptions). - `IgnoreSymbols` is not supported because there is no equivalent in native api. Throws `PlatformNotSupportedException`. diff --git a/src/libraries/Common/tests/Tests/System/StringTests.cs b/src/libraries/Common/tests/Tests/System/StringTests.cs index 359267c1c6fc20..45c3bce3c343a7 100644 --- a/src/libraries/Common/tests/Tests/System/StringTests.cs +++ b/src/libraries/Common/tests/Tests/System/StringTests.cs @@ -1034,10 +1034,12 @@ public static void CompareToNoMatch_StringComparison() var secondSpan = new ReadOnlySpan(second); Assert.True(0 > firstSpan.CompareTo(secondSpan, StringComparison.Ordinal)); - // Due to differences in the implementation, the exact result of CompareTo will not necessarily match with string.Compare. - // However, the sign will match, which is what defines correctness. + // On Apple platforms, string comparison is handled by native Apple functions, which apply normalization techniques + // like `precomposedStringWithCanonicalMapping`. This can lead to differences in behavior compared to other platforms. if (PlatformDetection.IsNotHybridGlobalizationOnApplePlatform) { + // Due to differences in the implementation, the exact result of CompareTo will not necessarily match with string.Compare. + // However, the sign will match, which is what defines correctness. Assert.Equal( Math.Sign(string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.OrdinalIgnoreCase)), Math.Sign(firstSpan.CompareTo(secondSpan, StringComparison.OrdinalIgnoreCase))); @@ -1313,9 +1315,11 @@ public static void ContainsNoMatch_StringComparison() Assert.False(firstSpan.Contains(secondSpan, StringComparison.OrdinalIgnoreCase)); - // Different behavior depending on OS + // On Apple platforms, string comparison is handled by native Apple functions, which apply normalization techniques + // like `precomposedStringWithCanonicalMapping`. This can lead to differences in behavior compared to other platforms. if (PlatformDetection.IsNotHybridGlobalizationOnApplePlatform) { + // Different behavior depending on OS Assert.Equal( firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.CurrentCulture), firstSpan.Contains(secondSpan, StringComparison.CurrentCulture)); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs index f3d2712faa1127..7e2277986c5ac2 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs @@ -37,6 +37,8 @@ public static class SqlStringSortingTest private static readonly UnicodeEncoding s_unicodeEncoding = new UnicodeEncoding(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: true); + // On Apple platforms, the string comparison implementation relies on native Apple functions which uses normalization techniques, which can result in behavior differences compared to other platforms. + // Specifically, the use of precomposed strings and additional locale-based string folding can affect the results of comparisons with certain options like `IgnoreKanaType`. [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization), nameof(PlatformDetection.IsNotHybridGlobalizationOnApplePlatform))] [InlineData("ja-JP", 0x0411)] // Japanese - Japan [InlineData("ar-SA", 0x0401)] // Arabic - Saudi Arabia diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.HashCode.cs b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.HashCode.cs index b915c8855f4661..aa05f00d4b6e69 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.HashCode.cs +++ b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.HashCode.cs @@ -14,6 +14,8 @@ public class CompareInfoHashCodeTests : CompareInfoTestsBase { [OuterLoop] + // On Apple platforms, string comparison is handled by native Apple functions, which apply normalization techniques + // like `precomposedStringWithCanonicalMapping`. This can lead to differences in behavior compared to other platforms. [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization), nameof(PlatformDetection.IsNotHybridGlobalizationOnApplePlatform))] public void CheckHashingInLineWithEqual() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs index a9936fce7ffdf4..ef51adaecc6a58 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs @@ -1982,6 +1982,9 @@ public static IEnumerable Parse_ValidInput_Succeeds_MemberData() yield return new object[] { "#2020-5-7T09:37:00.0000000+00:00#\0", CultureInfo.InvariantCulture, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(2020, 5, 7, 9, 37, 0, DateTimeKind.Utc), TimeZoneInfo.Local) }; yield return new object[] { "2020-5-7T09:37:00.0000000+00:00", CultureInfo.InvariantCulture, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(2020, 5, 7, 9, 37, 0, DateTimeKind.Utc), TimeZoneInfo.Local) }; + // On Apple platforms, the handling calendars relies on native Apple APIs (NSCalendar). + // These APIs can cause differences in behavior when parsing or formatting dates compared to other platforms. + // Specifically, the way Apple handles calendar identifiers and date formats for cultures like "he-IL" may lead to variations in the output. if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnApplePlatform) { DateTime today = DateTime.Today; From a00f04c4a60d9501e2efe28d8eefd5c3673ce6ec Mon Sep 17 00:00:00 2001 From: Meri Khamoyan Date: Thu, 26 Sep 2024 17:35:31 +0200 Subject: [PATCH 4/4] fix spaces in doc --- docs/design/features/globalization-hybrid-mode.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/design/features/globalization-hybrid-mode.md b/docs/design/features/globalization-hybrid-mode.md index 9e5b7ec7da5ccd..1dec94595b1c45 100644 --- a/docs/design/features/globalization-hybrid-mode.md +++ b/docs/design/features/globalization-hybrid-mode.md @@ -398,9 +398,10 @@ Affected public APIs: - String.Compare, - String.Equals. -Mapped to Apple Native API `compare:options:range:locale:`(https://developer.apple.com/documentation/foundation/nsstring/1414561-compare?language=objc)// This implementation uses normalization techniques such as `precomposedStringWithCanonicalMapping`, which can result in -behavior differences compared to other platforms. -Specifically, the use of precomposed strings and additional locale-based string folding can affect the results of comparisons. +Mapped to Apple Native API `compare:options:range:locale:`(https://developer.apple.com/documentation/foundation/nsstring/1414561-compare?language=objc) +This implementation uses normalization techniques such as `precomposedStringWithCanonicalMapping`, +which can result in behavior differences compared to other platforms. +Specifically, the use of precomposed strings and additional locale-based string folding can affect the results of comparisons. Due to these differences, the exact result of string compariso on Apple platforms may differ. The number of `CompareOptions` and `NSStringCompareOptions` combinations are limited. Originally supported combinations can be found [here for CompareOptions](https://learn.microsoft.com/dotnet/api/system.globalization.compareoptions) and [here for NSStringCompareOptions](https://developer.apple.com/documentation/foundation/nsstringcompareoptions).