ci: use windows 2025 runners (#7048)

* `windows-2022` → `windows-2025`
`windows-2019` → `windows-2022`

* Use windows icu by default

* Link against "new" `icu.lib` on windows.

https://learn.microsoft.com/en-us/windows/win32/intl/international-components-for-unicode--icu-#version-1903-may-2019-update

* Fix `Intl.getCanonicalLocales` tests

* Check icu version dynamically for windows

* Assume windows version will always be >= 62

* Update `ES6_intl_simple_attach.js` baseline

* Remove `require_winglob`

* Remove bi-di chars from `IntlReturnedValueTests.js` baseline

* Add comment to explain `ICU_VERSION` conditional-compilation.

* Check for existence of `icu.dll` in system32
diff --git a/Build/Chakra.Build.Default.props b/Build/Chakra.Build.Default.props
index 5501dbf..8566840 100644
--- a/Build/Chakra.Build.Default.props
+++ b/Build/Chakra.Build.Default.props
@@ -29,10 +29,20 @@
     <EnableIntl Condition="'$(EnableIntl)'==''">true</EnableIntl>
     <EnableIntl Condition="'$(BuildLite)'=='true'">false</EnableIntl>
 
-    <ChakraICU Condition="'$(ChakraICU)'==''">false</ChakraICU>
+    <ChakraICU Condition="'$(ChakraICU)'==''">windows</ChakraICU>
 
     <BuildChakraICUData Condition="'$(BuildChakraICUData)'=='' AND ('$(ChakraICU)'=='static' OR '$(ChakraICU)'=='shared')">true</BuildChakraICUData>
-
-    <IcuLibraryDependencies Condition="'$(ChakraICU)'=='windows'">icuuc.lib;icuin.lib</IcuLibraryDependencies>
   </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(ChakraICU)' == 'windows' ">
+    <_UseModernWindowsIcu Condition=" Exists('$(SYSTEMROOT)\System32\icu.dll') ">true</_UseModernWindowsIcu>
+
+    <IcuLibraryDependencies Condition=" '$(_UseModernWindowsIcu)' == 'true' ">icu.lib</IcuLibraryDependencies>
+    <IcuLibraryDependencies Condition=" '$(_UseModernWindowsIcu)' != 'true' ">icuuc.lib;icuin.lib</IcuLibraryDependencies>
+  </PropertyGroup>
+
+  <Target Name="CheckIcuDependency" Condition=" '$(ChakraICU)' == 'windows' " BeforeTargets="Build">
+    <Warning Condition=" '$(_UseModernWindowsIcu)' != 'true' " Code="CCICU001" Text="You are compiling against an old version of libicu." />
+  </Target>
+
 </Project>
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 7b98a59..33d2173 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -125,7 +125,7 @@
       maxParallel: 4
       matrix:
         x86.Debug:
-          image_name: 'windows-2022'
+          image_name: 'windows-2025'
           build_type: 'debug'
           target: 'x86'
           special_build: ''
@@ -133,7 +133,7 @@
           test_tags: ''
           build_outdir_suffix: ''
         x86.Test:
-          image_name: 'windows-2022'
+          image_name: 'windows-2025'
           build_type: 'test'
           target: 'x86'
           special_build: ''
@@ -141,7 +141,7 @@
           test_tags: '--include-slow'
           build_outdir_suffix: ''
         x86.NoJit:
-          image_name: 'windows-2022'
+          image_name: 'windows-2025'
           build_type: 'debug'
           target: 'x86'
           special_build: '"/p:BuildJIT=false"'
@@ -149,7 +149,7 @@
           test_tags: '-disablejit'
           build_outdir_suffix: '.NoJIT'
         x86.Release:
-          image_name: 'windows-2022'
+          image_name: 'windows-2025'
           build_type: 'release'
           target: 'x86'
           special_build: ''
@@ -157,7 +157,7 @@
           test_tags: ''
           build_outdir_suffix: ''
         x64.Debug:
-          image_name: 'windows-2022'
+          image_name: 'windows-2025'
           build_type: 'debug'
           target: 'x64'
           special_build: ''
@@ -165,7 +165,7 @@
           test_tags: ''
           build_outdir_suffix: ''
         x64.Test:
-          image_name: 'windows-2022'
+          image_name: 'windows-2025'
           build_type: 'test'
           target: 'x64'
           special_build: ''
@@ -173,23 +173,23 @@
           test_tags: '--include-slow'
           build_outdir_suffix: ''
         x64.Release:
-          image_name: 'windows-2022'
+          image_name: 'windows-2025'
           build_type: 'release'
           target: 'x64'
           special_build: ''
           do_test: false
           test_tags: ''
           build_outdir_suffix: ''
-        win19.x86.Release:
-          image_name: 'windows-2019'
+        win22.x86.Release:
+          image_name: 'windows-2022'
           build_type: 'release'
           target: 'x86'
           special_build: ''
           do_test: false
           test_tags: ''
           build_outdir_suffix: ''
-        win19.x64.Release:
-          image_name: 'windows-2019'
+        win22.x64.Release:
+          image_name: 'windows-2022'
           build_type: 'release'
           target: 'x64'
           special_build: ''
diff --git a/lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp b/lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp
index 4468712..8841197 100644
--- a/lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp
+++ b/lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp
@@ -2437,7 +2437,8 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
             return JavascriptString::NewWithBuffer(formatted, formattedLen, scriptContext);
         }
 
-#if defined(ICU_VERSION) && ICU_VERSION >= 61
+        // windows-icu does not define `ICU_VERSION` but does support `unum_formatDoubleForFields` (ICU 61+) since Windows 10 1809 "Redstone 5" (`NTDDI_WIN10_RS5`).
+#if !defined(ICU_VERSION) || ICU_VERSION >= 61
         UErrorCode status = U_ZERO_ERROR;
         ScopedUFieldPositionIterator fpi(ufieldpositer_open(&status));
 
@@ -3012,7 +3013,9 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
         // For ICU < 61, we can fake it by creating an array of ["other"], which
         // uplrules_getKeywords is guaranteed to return at minimum.
         // This array is only used in resolved options, so the majority of the functionality can remain (namely, select() still works)
-#if defined(ICU_VERSION) && ICU_VERSION >= 61
+        // 
+        // windows-icu does not define `ICU_VERSION` but does support `uplrules_getKeywords` (ICU 61+) since Windows 10 1809 "Redstone 5" (`NTDDI_WIN10_RS5`).
+#if !defined(ICU_VERSION) || ICU_VERSION >= 61
         DynamicObject *state = UnsafeVarTo<DynamicObject>(args[1]);
         FinalizableUPluralRules *pr = GetOrCreateCachedUPluralRules(state, scriptContext);
 
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 4e569d9..d66b8c1 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -8,8 +8,6 @@
 
 if (NO_ICU)
     set(TEST_ICU --not-tag exclude_noicu)
-elseif (NOT EMBED_ICU)
-    set(TEST_ICU --not-tag exclude_icu62AndAboveTestFailures)
 endif()
 
 if (BuildJIT)
diff --git a/test/DebuggerCommon/ES6_intl_simple_attach.js.dbg.baseline b/test/DebuggerCommon/ES6_intl_simple_attach.js.dbg.baseline
index da61b14..7ca8fce 100644
--- a/test/DebuggerCommon/ES6_intl_simple_attach.js.dbg.baseline
+++ b/test/DebuggerCommon/ES6_intl_simple_attach.js.dbg.baseline
@@ -131,7 +131,7 @@
               "#__proto__": "Object {...}",

               "constructor": "function <large string>",

               "resolvedOptions": "function <large string>",

-              "compare": "function <large string>"

+              "compare": "Error <large string>"

             },

             "length": "number 0",

             "name": "string Collator",

@@ -281,7 +281,8 @@
               "#__proto__": "Object {...}",

               "constructor": "function <large string>",

               "resolvedOptions": "function <large string>",

-              "format": "function <large string>"

+              "format": "Error <large string>",

+              "formatToParts": "function <large string>"

             },

             "length": "number 0",

             "name": "string NumberFormat",

@@ -323,6 +324,23 @@
               "arguments": "Error <large string>"

             },

             "length": "number 1"

+          },

+          "formatToParts": {

+            "#__proto__": {

+              "#__proto__": "Object {...}",

+              "constructor": "function <large string>",

+              "length": "number 0",

+              "name": "string ",

+              "apply": "function <large string>",

+              "bind": "function <large string>",

+              "call": "function <large string>",

+              "toString": "function <large string>",

+              "Symbol.hasInstance": "function <large string>",

+              "caller": "Error <large string>",

+              "arguments": "Error <large string>"

+            },

+            "length": "number 1",

+            "name": "string formatToParts"

           }

         }

       }

@@ -430,17 +448,12 @@
             "prototype": {

               "#__proto__": "Object {...}",

               "constructor": "function <large string>",

-              "format": "function <large string>",

+              "format": "Error <large string>",

+              "formatToParts": "function <large string>",

               "resolvedOptions": "function <large string>"

             },

             "length": "number 0",

             "name": "string DateTimeFormat",

-            "__relevantExtensionKeys": {

-              "#__proto__": "Array []",

-              "length": "number 2",

-              "[0]": "string \"ca\"",

-              "[1]": "string \"nu\""

-            },

             "supportedLocalesOf": {

               "#__proto__": "function <large string>",

               "length": "number 1",

@@ -463,6 +476,23 @@
             },

             "length": "number 1"

           },

+          "formatToParts": {

+            "#__proto__": {

+              "#__proto__": "Object {...}",

+              "constructor": "function <large string>",

+              "length": "number 0",

+              "name": "string ",

+              "apply": "function <large string>",

+              "bind": "function <large string>",

+              "call": "function <large string>",

+              "toString": "function <large string>",

+              "Symbol.hasInstance": "function <large string>",

+              "caller": "Error <large string>",

+              "arguments": "Error <large string>"

+            },

+            "length": "number 1",

+            "name": "string formatToParts"

+          },

           "resolvedOptions": {

             "#__proto__": {

               "#__proto__": "Object {...}",

diff --git a/test/DebuggerCommon/rlexe.xml b/test/DebuggerCommon/rlexe.xml
index d7ecbd8..3bbdd01 100644
--- a/test/DebuggerCommon/rlexe.xml
+++ b/test/DebuggerCommon/rlexe.xml
@@ -218,8 +218,7 @@
       <files>ES6_intl_simple_attach.js</files>
       <compile-flags>-dbgbaseline:ES6_intl_simple_attach.js.dbg.baseline -Intl</compile-flags>
       <baseline>ES6_intl_simple_attach.js.baseline</baseline>
-      <!-- This test is still require_winglob because it has winglob-specific output in the .dbg.baseline -->
-      <tags>Intl,require_winglob</tags>
+      <tags>Intl</tags>
     </default>
   </test>
   <test>
diff --git a/test/Intl/GetCanonicalLocales.js b/test/Intl/GetCanonicalLocales.js
index 2fe70ec..02983ae 100644
--- a/test/Intl/GetCanonicalLocales.js
+++ b/test/Intl/GetCanonicalLocales.js
@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------

 // Copyright (C) Microsoft. All rights reserved.

+// Copyright (c) ChakraCore Project Contributors. All rights reserved.

 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

 //-------------------------------------------------------------------------------------------------------

 

@@ -90,9 +91,15 @@
             // V8 and CC-ICU also give the default value of "yes" to non-boolean keys (co), which also is incorrect.

             // Everyone (should) correctly re-order extension keys alphabetically

             // Microsoft/ChakraCore#4490 tracks the incorrect defaulting, Microsoft/ChakraCore#2964 tracks the overall investigation

-            equal("de-DE-u-co-kn", "de-DE-u-co-yes-kn-true", gcl("de-de-u-kn-co")[0]);

-            equal("de-DE-u-co-phonebk-kn", "de-DE-u-co-phonebk-kn-true", gcl("de-de-u-kn-co-phonebk")[0]);

-            equal("de-DE-u-co-phonebk-kn-yes", "de-DE-u-co-phonebk-kn-true", gcl("de-DE-u-kn-yes-co-phonebk")[0]);

+            if (WScript.Platform.ICU_VERSION < 62) {

+                assert.areEqual(["de-DE-u-co-yes-kn-true"], Intl.getCanonicalLocales("de-de-u-kn-co"))

+                assert.areEqual(["de-DE-u-co-phonebk-kn-true"], Intl.getCanonicalLocales("de-de-u-kn-co-phonebk"))

+                assert.areEqual(["de-DE-u-co-phonebk-kn-true"], Intl.getCanonicalLocales("de-DE-u-kn-yes-co-phonebk"))

+            } else {

+                assert.areEqual(["de-DE-u-co-kn"], Intl.getCanonicalLocales("de-de-u-kn-co"))

+                assert.areEqual(["de-DE-u-co-phonebk-kn"], Intl.getCanonicalLocales("de-de-u-kn-co-phonebk"))

+                assert.areEqual(["de-DE-u-co-phonebk-kn"], Intl.getCanonicalLocales("de-DE-u-kn-yes-co-phonebk"))

+            }

 

             // De-dupe after locales are canonicalized

             assert.areEqual(Intl.getCanonicalLocales(['en-us', 'en-us']), ['en-US'], "No duplicates, same input casing (casing was incorrect)");

@@ -100,8 +107,8 @@
             assert.areEqual(Intl.getCanonicalLocales(['en-us', 'en-US']), ['en-US'], "No duplicates, different input casing");

 

             assert.areEqual(

+                ["de-DE", "de-DE-u-co-phonebk-kn"],

                 Intl.getCanonicalLocales(["de-de", "de-DE-u-co-phonebk-kn-true", "de-DE-u-kn-true-co-phonebk"]),

-                ["de-DE", "de-DE-u-co-phonebk-kn-true"],

                 "No duplicates after re-ordering options"

             );

         }

@@ -122,8 +129,12 @@
             // TODO (doilij): Investigate what is correct/allowable here (Microsoft/ChakraCore#2964)

             equal("xx-zzz", "zzz", gcl("xx-zzz")[0]);

 

-            // See discussion of defaulting above (V8/CC-ICU and CC-WinGlob/SM distinction remains true here)

-            equal("xx-ZZ-u-yy-zz", "xx-ZZ-u-yy-yes-zz-yes", gcl("xx-zz-u-zz-yy")[0]);

+            // See discussion of defaulting above

+            if (WScript.Platform.ICU_VERSION < 62) {

+                assert.areEqual(["xx-ZZ-u-yy-yes-zz-yes"], Intl.getCanonicalLocales("xx-zz-u-zz-yy"));

+            } else {

+                assert.areEqual(["xx-ZZ-u-yy-zz"], Intl.getCanonicalLocales("xx-zz-u-zz-yy"));

+            }

         }

     },

     {

diff --git a/test/Intl/IntlReturnedValueTests.js.dbg.baseline b/test/Intl/IntlReturnedValueTests.js.dbg.baseline
index 8270a3c..c1c1eeb 100644
--- a/test/Intl/IntlReturnedValueTests.js.dbg.baseline
+++ b/test/Intl/IntlReturnedValueTests.js.dbg.baseline
@@ -21,14 +21,14 @@
     "this": "Object {...}",

     "functionCallsReturn": {

       "[get format returned]": "function <large string>",

-      "[Intl.DateTimeFormat.prototype.format returned]": "string ‎2‎/‎1‎/‎2000"

+      "[Intl.DateTimeFormat.prototype.format returned]": "string 2/1/2000"

     },

     "locals": {

       "Symbol.toStringTag": "string global",

       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "undefined undefined",

       "numberFormat1": "undefined undefined",

       "formattedNumber1": "undefined undefined",

@@ -46,7 +46,7 @@
       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "undefined undefined",

       "formattedNumber1": "undefined undefined",

@@ -64,7 +64,7 @@
       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "undefined undefined",

       "formattedNumber1": "undefined undefined",

@@ -75,14 +75,14 @@
   {

     "this": "Object {...}",

     "functionCallsReturn": {

-      "[resolvedOptions returned]": "Object {...}"

+      "[Intl.DateTimeFormat.prototype.resolvedOptions returned]": "Object {...}"

     },

     "locals": {

       "Symbol.toStringTag": "string global",

       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "undefined undefined",

       "formattedNumber1": "undefined undefined",

@@ -100,7 +100,7 @@
       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "Object {...}",

       "formattedNumber1": "undefined undefined",

@@ -119,7 +119,7 @@
       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "Object {...}",

       "formattedNumber1": "string 123.456",

@@ -137,7 +137,7 @@
       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "Object {...}",

       "formattedNumber1": "string 123.456",

@@ -148,14 +148,14 @@
   {

     "this": "Object {...}",

     "functionCallsReturn": {

-      "[resolvedOptions returned]": "Object {...}"

+      "[Intl.NumberFormat.prototype.resolvedOptions returned]": "Object {...}"

     },

     "locals": {

       "Symbol.toStringTag": "string global",

       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "Object {...}",

       "formattedNumber1": "string 123.456",

@@ -173,7 +173,7 @@
       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "Object {...}",

       "formattedNumber1": "string 123.456",

@@ -192,7 +192,7 @@
       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "Object {...}",

       "formattedNumber1": "string 123.456",

@@ -210,7 +210,7 @@
       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "Object {...}",

       "formattedNumber1": "string 123.456",

@@ -221,14 +221,14 @@
   {

     "this": "Object {...}",

     "functionCallsReturn": {

-      "[resolvedOptions returned]": "Object {...}"

+      "[Intl.Collator.prototype.resolvedOptions returned]": "Object {...}"

     },

     "locals": {

       "Symbol.toStringTag": "string global",

       "options": "Object {...}",

       "dateFormat1": "Object {...}",

       "date1": "Date <large string>",

-      "date2": "string ‎2‎/‎1‎/‎2000",

+      "date2": "string 2/1/2000",

       "stringDate1": "string <large string>",

       "numberFormat1": "Object {...}",

       "formattedNumber1": "string 123.456",

diff --git a/test/Intl/rlexe.xml b/test/Intl/rlexe.xml
index 33910ad..2e2ba88 100644
--- a/test/Intl/rlexe.xml
+++ b/test/Intl/rlexe.xml
@@ -23,7 +23,7 @@
   <test>
     <default>
       <files>NumberFormat.js</files>
-      <tags>Intl,exclude_drt,exclude_icu62AndAboveTestFailures</tags>
+      <tags>Intl,exclude_drt</tags>
     </default>
   </test>
   <test>
@@ -37,7 +37,7 @@
     <default>
       <files>GetCanonicalLocales.js</files>
       <compile-flags>-args summary -endargs</compile-flags>
-      <tags>Intl,exclude_icu62AndAboveTestFailures</tags>
+      <tags>Intl</tags>
     </default>
   </test>
   <test>
@@ -84,7 +84,7 @@
     <default>
       <compile-flags> -Intl -debugLaunch -dbgbaseline:IntlReturnedValueTests.js.dbg.baseline</compile-flags>
       <files>IntlReturnedValueTests.js</files>
-      <tags>Intl,require_winglob</tags> <!-- require_winglob because the baseline contains embedded bi-di markers -->
+      <tags>Intl</tags>
     </default>
   </test>
   <test>
diff --git a/test/runtests.py b/test/runtests.py
index 4a7d811..f2dcd4c 100755
--- a/test/runtests.py
+++ b/test/runtests.py
@@ -175,7 +175,6 @@
 # xplat: temp hard coded to exclude unsupported tests
 if sys.platform != 'win32':
     not_tags.add('exclude_xplat')
-    not_tags.add('require_winglob')
     not_tags.add('require_simd')
 else:
     not_tags.add('exclude_windows')