From e0facb82e0a5273076c517c8d1b57ad9ca6b647c Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Wed, 31 Jul 2024 11:15:59 +0700 Subject: [PATCH 1/6] add dotnet 8 as a target framework for SIL.WritingSystems.Tests. Also add a test to exhibit an issue with icu.net and SIL.WritingSystems when using net8.0 --- .../IcuRulesCollationDefinitionTests.cs | 16 ++++++++++++++++ .../SIL.WritingSystems.Tests.csproj | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/SIL.WritingSystems.Tests/IcuRulesCollationDefinitionTests.cs b/SIL.WritingSystems.Tests/IcuRulesCollationDefinitionTests.cs index d447688d4..c937c3eb2 100644 --- a/SIL.WritingSystems.Tests/IcuRulesCollationDefinitionTests.cs +++ b/SIL.WritingSystems.Tests/IcuRulesCollationDefinitionTests.cs @@ -80,5 +80,21 @@ public void Validate_ImportInvalidRules_NotValid() Assert.That(collation.Validate(out message), Is.False); Assert.That(message, Is.EqualTo("Unable to import the private collation rules from en-US.")); } + + [Test] + public void Collation_GetSortKeyWorks() + { + var ws = new WritingSystemDefinition("en-US"); + ws.Collations.Add(new IcuRulesCollationDefinition("private") + { IcuRules = "&B + $(TargetFrameworks);net8.0 Unit tests for SIL.WritingSystems @@ -8,8 +9,11 @@ + + + From 2acf12f19e76974685884811bf9f3e06ce5946b6 Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Wed, 31 Jul 2024 12:13:22 +0700 Subject: [PATCH 2/6] fix unit test detection which caused tests to fail when running on dotnet 8 --- SIL.Core/Reflection/ReflectionHelper.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/SIL.Core/Reflection/ReflectionHelper.cs b/SIL.Core/Reflection/ReflectionHelper.cs index c5cc016df..039948537 100644 --- a/SIL.Core/Reflection/ReflectionHelper.cs +++ b/SIL.Core/Reflection/ReflectionHelper.cs @@ -1,6 +1,7 @@ using SIL.IO; using System; using System.IO; +using System.Linq; using System.Reflection; namespace SIL.Reflection @@ -461,13 +462,24 @@ public static string LongVersionNumberString } } + private static readonly bool RunningFromUnitTest = AppDomain.CurrentDomain.GetAssemblies() + .Any(assem => + assem.FullName.StartsWith("nunit.framework", StringComparison.OrdinalIgnoreCase) + || assem.FullName.StartsWith( + "Microsoft.VisualStudio.QualityTools.UnitTestFramework", + StringComparison.OrdinalIgnoreCase) + || assem.FullName.StartsWith("Microsoft.VisualStudio.TestPlatform.TestFramework", + StringComparison.OrdinalIgnoreCase) + || assem.FullName.StartsWith("xunit.core", StringComparison.OrdinalIgnoreCase) + ); + public static string DirectoryOfTheApplicationExecutable { get { string path; bool unitTesting = Assembly.GetEntryAssembly() == null; - if (unitTesting) + if (RunningFromUnitTest || unitTesting) { path = new Uri(Assembly.GetExecutingAssembly().CodeBase).AbsolutePath; path = Uri.UnescapeDataString(path); From 8123e3e8f5e5ca499fb9d2b2fd3ae0f73a28e8e8 Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Wed, 31 Jul 2024 12:29:56 +0700 Subject: [PATCH 3/6] update test adapter to work in the presence of dotnet 8 --- SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj b/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj index de5f17de3..a2e412248 100644 --- a/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj +++ b/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj @@ -14,7 +14,7 @@ - + From e41a6e1f8d80b8157d0fe415a658793944ea51fa Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Wed, 31 Jul 2024 12:58:40 +0700 Subject: [PATCH 4/6] add a helper method to detect unknown cultures, use that instead of checking for "Unknown Language" in the name. Fixes a number of tests that were failing due to incorrectly detecting unknown cultures. --- SIL.WritingSystems/CultureInfoExtensions.cs | 18 ++++++++++++++++++ SIL.WritingSystems/IetfLanguageTag.cs | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 SIL.WritingSystems/CultureInfoExtensions.cs diff --git a/SIL.WritingSystems/CultureInfoExtensions.cs b/SIL.WritingSystems/CultureInfoExtensions.cs new file mode 100644 index 000000000..e49121074 --- /dev/null +++ b/SIL.WritingSystems/CultureInfoExtensions.cs @@ -0,0 +1,18 @@ +using System.Globalization; + +namespace SIL.WritingSystems +{ + public static class CultureInfoExtensions + { + public static bool IsUnknownCulture(this CultureInfo cultureInfo) + { + // Windows 10 changed the behavior of CultureInfo, in that unknown cultures no longer return a CultureInfo containing an "Unknown Language" indication. + // The proper way to detect fully unknown cultures (for Windows 11 and prior) is to: + // 1. Check for the custom culture flag + // 2. Check if the three-letter language name is set to default + // Source: https://stackoverflow.com/a/71388328/1964319 + return cultureInfo.CultureTypes.HasFlag(CultureTypes.UserCustomCulture) && + cultureInfo.ThreeLetterWindowsLanguageName == "ZZZ"; + } + } +} \ No newline at end of file diff --git a/SIL.WritingSystems/IetfLanguageTag.cs b/SIL.WritingSystems/IetfLanguageTag.cs index b2f984fe1..ad3b3f45c 100644 --- a/SIL.WritingSystems/IetfLanguageTag.cs +++ b/SIL.WritingSystems/IetfLanguageTag.cs @@ -1350,7 +1350,7 @@ public static string GetLocalizedLanguageName(string languageTag, string uiLangu } if (IsNullOrWhiteSpace(langName)) langName = ci.EnglishName; - if (!ci.EnglishName.StartsWith("Unknown Language")) // Windows .Net behavior + if (!ci.IsUnknownCulture()) { MapIsoCodesToLanguageName.Add(key, langName); return langName; @@ -1435,7 +1435,7 @@ public static string GetNativeLanguageNameWithEnglishSubtitle(string code) englishNameSuffix = englishNameSuffix.Substring(0, idxCountry) + "))"; } langName = nativeName + englishNameSuffix; - if (!ci.EnglishName.StartsWith("Unknown Language")) // Windows .Net behavior + if (!ci.IsUnknownCulture()) { MapIsoCodeToSubtitledLanguageName.Add(code, langName); return langName; From 92e5fe2460e17d63c20f98617ab8e09c27e203fb Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Wed, 31 Jul 2024 13:04:07 +0700 Subject: [PATCH 5/6] don't use ICU when running writing system tests as many of them are over specified and expect NLS (Windows only globalization) to be used instead of ICU. --- SIL.WritingSystems.Tests/AddSortKeysToXmlTests.cs | 11 +++++++++++ .../SIL.WritingSystems.Tests.csproj | 3 +++ 2 files changed, 14 insertions(+) diff --git a/SIL.WritingSystems.Tests/AddSortKeysToXmlTests.cs b/SIL.WritingSystems.Tests/AddSortKeysToXmlTests.cs index dc4c1e848..12b30edeb 100644 --- a/SIL.WritingSystems.Tests/AddSortKeysToXmlTests.cs +++ b/SIL.WritingSystems.Tests/AddSortKeysToXmlTests.cs @@ -3,6 +3,7 @@ using System.Xml; using System.Xml.XPath; using NUnit.Framework; +using SIL.Base32; namespace SIL.WritingSystems.Tests { @@ -40,6 +41,16 @@ public void Setup() _sortKeyGenerator = CultureInfo.InvariantCulture.CompareInfo.GetSortKey; } + [Test] + public void VerifySortKeyGenerator() + { + var sortKey = _sortKeyGenerator("z"); + var sortKeyBase32 = Base32Convert.ToBase32HexString(sortKey.KeyData, Base32FormattingOptions.None); + //this may be over specified, but all the tests expect this to pass + Assert.AreEqual("1QKG20810400", sortKeyBase32); + Assert.AreEqual("z", sortKey.OriginalString); + } + [Test] public void AddSortKeys() { diff --git a/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj b/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj index a2e412248..75dbb5d26 100644 --- a/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj +++ b/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj @@ -4,6 +4,9 @@ $(TargetFrameworks);net8.0 Unit tests for SIL.WritingSystems + + + From 7dd278988484f3f3e8e26b5938e9f1f7b36c8f37 Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Thu, 1 Aug 2024 16:29:12 +0700 Subject: [PATCH 6/6] update to icu.net 2.10.1-beta.6 --- .../SIL.WritingSystems.Tests.csproj | 2 +- SIL.WritingSystems/IcuRulesCollator.cs | 49 ------------------- SIL.WritingSystems/SIL.WritingSystems.csproj | 2 +- 3 files changed, 2 insertions(+), 51 deletions(-) diff --git a/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj b/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj index b143dcd73..dd45d6b3e 100644 --- a/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj +++ b/SIL.WritingSystems.Tests/SIL.WritingSystems.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/SIL.WritingSystems/IcuRulesCollator.cs b/SIL.WritingSystems/IcuRulesCollator.cs index d3b4a7147..fd6fac7ea 100644 --- a/SIL.WritingSystems/IcuRulesCollator.cs +++ b/SIL.WritingSystems/IcuRulesCollator.cs @@ -62,37 +62,7 @@ public static bool ValidateSortRules(string rules, out string message) public SortKey GetSortKey(string source) { -#if NET461 return _collator.GetSortKey(source); -#elif NETSTANDARD2_0 - Icu.SortKey icuSortKey = _collator.GetSortKey(source); - SortKey sortKey = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(string.Empty, CompareOptions.None); - string keyDataFieldName, origStringFieldName; - if (Platform.IsDotNetFramework) - { - keyDataFieldName = "m_KeyData"; - origStringFieldName = "m_String"; - } - else if (Platform.IsDotNetCore) - { - keyDataFieldName = "_keyData"; - origStringFieldName = "_string"; - } - else if (Platform.IsMono) - { - keyDataFieldName = "key"; - origStringFieldName = "source"; - } - else - { - throw new PlatformNotSupportedException(); - } - - SetInternalFieldForPublicProperty(sortKey, "SortKey.KeyData", keyDataFieldName, icuSortKey.KeyData); - SetInternalFieldForPublicProperty(sortKey, "SortKey.OriginalString", origStringFieldName, - icuSortKey.OriginalString); - return sortKey; -#endif } ///Compares two strings and returns a value indicating whether one is less than, @@ -114,24 +84,5 @@ public int Compare(object x, object y) { return Compare((string) x, (string) y); } - -#if NETSTANDARD2_0 - private static void SetInternalFieldForPublicProperty(object instance, string propertyName, string fieldName, - object value) - { - Type type = instance.GetType(); - - FieldInfo fieldInfo = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); - - Debug.Assert(fieldInfo != null, - "Unsupported runtime", - "Could not figure out an internal field for" + propertyName); - - if (fieldInfo == null) - throw new PlatformNotSupportedException(); - - fieldInfo.SetValue(instance, value); - } -#endif } } diff --git a/SIL.WritingSystems/SIL.WritingSystems.csproj b/SIL.WritingSystems/SIL.WritingSystems.csproj index ca4f1b81b..d20cb55ad 100644 --- a/SIL.WritingSystems/SIL.WritingSystems.csproj +++ b/SIL.WritingSystems/SIL.WritingSystems.csproj @@ -12,7 +12,7 @@ - +