Przeglądaj źródła

Add Intl.platform for easier native method unit testing

Jack Horton 8 lat temu
rodzic
commit
52ad3402de

+ 3 - 1
lib/Common/ConfigFlagsList.h

@@ -387,6 +387,7 @@ PHASE(All)
 #else
 #define DEFAULT_CONFIG_BgJitDelay           (30)
 #endif
+#endif // DEFAULT_CONFIG_BgJitDelay
 #define DEFAULT_CONFIG_AsmJs                (true)
 #define DEFAULT_CONFIG_AsmJsEdge            (false)
 #define DEFAULT_CONFIG_AsmJsStopOnError     (false)
@@ -538,6 +539,7 @@ PHASE(All)
 
 #define DEFAULT_CONFIG_Intl                    (true)
 #define DEFAULT_CONFIG_IntlBuiltIns            (true)
+#define DEFAULT_CONFIG_IntlPlatform            (false) // Makes the EngineExtension.Intl object visible to user code as Intl.platform, meant for testing
 
 #ifdef ENABLE_JS_BUILTINS
     #define DEFAULT_CONFIG_JsBuiltIn             (true)
@@ -631,7 +633,6 @@ PHASE(All)
 #define DEFAULT_CONFIG_ForcePostLowerGlobOptInstrString (false)
 #define DEFAULT_CONFIG_EnumerateSpecialPropertiesInDebugger (true)
 #define DEFAULT_CONFIG_ESDynamicImport         (false)
-#endif
 
 #define DEFAULT_CONFIG_MaxJITFunctionBytecodeByteLength (4800000)
 #define DEFAULT_CONFIG_MaxJITFunctionBytecodeCount (120000)
@@ -1020,6 +1021,7 @@ FLAGNR(Boolean, CollectGarbage        , "Enable CollectGarbage API", DEFAULT_CON
 
 FLAGR (Boolean, Intl                  , "Intl object support", DEFAULT_CONFIG_Intl)
 FLAGNR(Boolean, IntlBuiltIns          , "Intl built-in function support", DEFAULT_CONFIG_IntlBuiltIns)
+FLAGNR(Boolean, IntlPlatform          , "Make the internal Intl native helper object visible to user code", DEFAULT_CONFIG_IntlPlatform)
 
 FLAGNR(Boolean, JsBuiltIn             , "JS Built-in function support", DEFAULT_CONFIG_JsBuiltIn)
 FLAGNR(Boolean, JitRepro              , "Add Function.invokeJit to execute codegen on an encoded rpc buffer", DEFAULT_CONFIG_JitRepro)

+ 1 - 0
lib/Runtime/Base/JnDirectFields.h

@@ -514,6 +514,7 @@ ENTRY(subTags)
 ENTRY(supportedLocalesOf)
 ENTRY(tagPublicLibraryCode)
 ENTRY(winglob)
+ENTRY(platform)
 
 ENTRY(NumberFormat)
 ENTRY(__currency)

+ 6 - 0
lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp

@@ -395,6 +395,12 @@ namespace Js
                 DynamicType::New(scriptContext, TypeIds_Object, commonObject, nullptr,
                     DeferredTypeHandler<InitializeIntlNativeInterfaces>::GetDefaultInstance()));
             library->AddMember(library->GetEngineInterfaceObject(), Js::PropertyIds::Intl, this->intlNativeInterfaces);
+
+            // Only show the platform object publicly if -IntlPlatform is passed
+            if (CONFIG_FLAG(IntlPlatform))
+            {
+                library->AddMember(library->GetIntlObject(), PropertyIds::platform, this->intlNativeInterfaces);
+            }
         }
 
         // TODO: JsBuiltIns fail without these being initialized here?

+ 1 - 1
lib/Runtime/Library/JavascriptLibraryBase.h

@@ -95,7 +95,7 @@ namespace Js
         DynamicObject* GetMathObject() { return mathObject; }
         DynamicObject* GetJSONObject() { return JSONObject; }
 #ifdef ENABLE_INTL_OBJECT
-        DynamicObject* GetINTLObject() { return IntlObject; }
+        DynamicObject* GetIntlObject() { return IntlObject; }
 #endif
 #if defined(ENABLE_INTL_OBJECT)  || defined(ENABLE_JS_BUILTINS) || defined(ENABLE_PROJECTION)
         EngineInterfaceObject* GetEngineInterfaceObject() { return engineInterfaceObject; }

+ 78 - 0
test/Intl/IntlPlatform.js

@@ -0,0 +1,78 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+
+if (Intl.platform === undefined) {
+    WScript.Echo("This test must be run with -IntlPlatform to enable the Intl.platform object");
+    WScript.Quit(1);
+} else if (WScript.Platform.INTL_LIBRARY === "winglob") {
+    // Skip for winglob -- there is an equivalent test in ChakraFull for it
+    WScript.Echo("pass");
+    WScript.Quit(0);
+}
+
+var platform = Intl.platform;
+Intl.platform.useCaches = false;
+
+/**
+ * Caches all methods on Intl.platform and restores them after the test executes
+ */
+function testSingleConstructor(Ctor, test) {
+    return function () {
+        const methods = Object.getOwnPropertyNames(Intl.platform);
+        const cache = {};
+
+        for (const method of methods) {
+            cache[method] = Intl.platform[method];
+        }
+
+        test(Ctor);
+
+        for (const method of methods) {
+            Intl.platform[method] = cache[method];
+        }
+    }
+}
+
+/**
+ * Creates a test for each constructor
+ */
+function testEachConstructor(name, test) {
+    const ret = [];
+    for (const Ctor of [Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat]) {
+        ret.push({
+            name: `${name} (using Intl.${Ctor.name})`,
+            body: testSingleConstructor(Ctor, test)
+        });
+    }
+    return ret;
+}
+
+const tests = [
+    ...testEachConstructor("Changing the default locale", function (Ctor) {
+        platform.getDefaultLocale = () => "de-DE";
+        assert.areEqual("de-DE", new Ctor().resolvedOptions().locale, "Default locale is respected with undefined language tag");
+    }),
+    ...testEachConstructor("Limiting available locales", function (Ctor) {
+        const isXLocaleAvailableMap = {
+            Collator: "Collator",
+            NumberFormat: "NF",
+            DateTimeFormat: "DTF",
+        };
+
+        const mapped = isXLocaleAvailableMap[Ctor.name];
+        assert.isNotUndefined(mapped, `Invalid test setup: no mapped name available for ${Ctor.name}`);
+
+        platform[`is${mapped}LocaleAvailable`] = (langtag) => ["de", "de-DE", "en", "zh", "en-UK"].includes(langtag);
+        platform.getDefaultLocale = () => "en-UK";
+        assert.areEqual("en", new Ctor("en-US").resolvedOptions().locale, "en-US should fall back to en");
+        assert.areEqual("zh", new Ctor("zh-Hans").resolvedOptions().locale, "zh-Hans should fall back to zh");
+        assert.areEqual("de-DE", new Ctor("de-DE-gregory").resolvedOptions().locale, "de-DE-gregory should fall back to de-DE");
+        assert.areEqual("en-UK", new Ctor("sp").resolvedOptions().locale, "An unknown language tag should fall back to the default");
+    })
+];
+
+testRunner.runTests(tests, { verbose: false });

+ 7 - 0
test/Intl/rlexe.xml

@@ -112,6 +112,13 @@
       <tags>Intl</tags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>IntlPlatform.js</files>
+      <compile-flags>-IntlPlatform</compile-flags>
+      <tags>Intl,exclude_windows</tags>
+    </default>
+  </test>
 
   <!-- Slow Tests -->
 

+ 2 - 0
test/JsBuiltIns/ChakraLib.js

@@ -11,6 +11,8 @@ var tests = [
         body: function () {
             assert.isNotUndefined(__chakraLibrary, "__chakraLibrary must NOT be undefined as we're using the -LdChakraLib flag.");
         },
+    },
+    {
         name: "Overriding __chakraLibrary must not work change the behavior.",
         body: function () {
             __chakraLibrary = -1;