Bug 1533719 - test_getTypeFromExtension_with_empty_Content_Type.js is not testing what it is supposed to test. r=Felipe
authorMarco Bonardo <mbonardo@mozilla.com>
Wed, 27 Mar 2019 15:17:18 +0000
changeset 466383 0339d18944be39dceb93fd6b46fc20c6b3f85725
parent 466382 79f99b532456a7d5b31537cd9d7db92cfc3654d7
child 466384 b0e059604791d865dc0773c1ba9a30c3e6a0203a
push id35768
push useropoprus@mozilla.com
push dateThu, 28 Mar 2019 09:55:54 +0000
treeherdermozilla-central@c045dd97faf2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersFelipe
bugs1533719, 568691
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1533719 - test_getTypeFromExtension_with_empty_Content_Type.js is not testing what it is supposed to test. r=Felipe The test was broken by a commit in bug 568691 and because the ".txt" extension skips the code under test, we never noticed that. Differential Revision: https://phabricator.services.mozilla.com/D25067
uriloader/exthandler/tests/unit/test_getTypeFromExtension_with_empty_Content_Type.js
uriloader/exthandler/tests/unit/xpcshell.ini
--- a/uriloader/exthandler/tests/unit/test_getTypeFromExtension_with_empty_Content_Type.js
+++ b/uriloader/exthandler/tests/unit/test_getTypeFromExtension_with_empty_Content_Type.js
@@ -3,185 +3,176 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * Test for bug 484579 <https://bugzilla.mozilla.org/show_bug.cgi?id=484579>:
  * nsIMIMEService.getTypeFromExtension may fail unexpectedly on Windows when
  * "Content Type" is empty in the registry.
  */
+
+// We must use a file extension that isn't listed in nsExternalHelperAppService's
+// defaultMimeEntries, otherwise the code takes a shortcut skipping the registry.
+const FILE_EXTENSION = ".nfo";
+// This is used to ensure the test properly used the mock, so that if we change
+// the underlying code, it won't be skipped.
+let gTestUsedOurMock = false;
+
 function run_test() {
-  // --- Preliminary platform check ---
+  // Activate the override of the file association data in the registry.
+  registerMockWindowsRegKeyFactory();
 
-  // If this test is not running on the Windows platform, stop now, before
-  // calling ChromeUtils.generateQI during the MockWindowsRegKey declaration.
-  if (mozinfo.os != "win")
-    return;
-
-  // --- Modified nsIWindowsRegKey implementation ---
+  // Check the mock has been properly activated.
+  let regKey = Cc["@mozilla.org/windows-registry-key;1"]
+                 .createInstance(Ci.nsIWindowsRegKey);
+  regKey.open(Ci.nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT, FILE_EXTENSION,
+              Ci.nsIWindowsRegKey.ACCESS_QUERY_VALUE);
+  Assert.equal(regKey.readStringValue("content type"), "",
+               "Check the mock replied as expected.");
+  Assert.ok(gTestUsedOurMock, "The test properly used the mock registry");
+  // Reset gTestUsedOurMock, because we just used it.
+  gTestUsedOurMock = false;
+  // Try and get the MIME type associated with the extension. If this
+  // operation does not throw an unexpected exception, the test succeeds.
+  Assert.throws(() => {
+    Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService)
+                             .getTypeFromExtension(FILE_EXTENSION);
+  }, /NS_ERROR_NOT_AVAILABLE/, "Should throw a NOT_AVAILABLE exception");
 
-  /**
-   * Constructs a new mock registry key by wrapping the provided object.
-   *
-   * This mock implementation is tailored for this test, and forces consumers
-   * of the readStringValue method to believe that the "Content Type" value of
-   * the ".txt" key under HKEY_CLASSES_ROOT is an empty string.
-   *
-   * The same value read from "HKEY_LOCAL_MACHINE\SOFTWARE\Classes" is not
-   * affected.
-   *
-   * @param aWrappedObject   An actual nsIWindowsRegKey implementation.
-   */
-  function MockWindowsRegKey(aWrappedObject) {
-    this._wrappedObject = aWrappedObject;
+  Assert.ok(gTestUsedOurMock, "The test properly used the mock registry");
+}
 
-    // This function creates a forwarding function for wrappedObject
-    function makeForwardingFunction(functionName) {
-      return function() {
-        return aWrappedObject[functionName].apply(aWrappedObject, arguments);
-      };
-    }
+/**
+ * Constructs a new mock registry key by wrapping the provided object.
+ *
+ * This mock implementation is tailored for this test, and forces consumers
+ * of the readStringValue method to believe that the "Content Type" value of
+ * the FILE_EXTENSION key under HKEY_CLASSES_ROOT is an empty string.
+ *
+ * The same value read from "HKEY_LOCAL_MACHINE\SOFTWARE\Classes" is not
+ * affected.
+ *
+ * @param aWrappedObject   An actual nsIWindowsRegKey implementation.
+ */
+function MockWindowsRegKey(aWrappedObject) {
+  this._wrappedObject = aWrappedObject;
 
-    // Forward all the functions that are not explicitly overridden
-    for (var propertyName in aWrappedObject) {
-      if (!(propertyName in this)) {
-        if (typeof aWrappedObject[propertyName] == "function") {
-          this[propertyName] = makeForwardingFunction(propertyName);
-        } else {
-          this[propertyName] = aWrappedObject[propertyName];
-        }
+  // This function creates a forwarding function for wrappedObject
+  function makeForwardingFunction(functionName) {
+    return function() {
+      return aWrappedObject[functionName].apply(aWrappedObject, arguments);
+    };
+  }
+
+  // Forward all the functions that are not explicitly overridden
+  for (var propertyName in aWrappedObject) {
+    if (!(propertyName in this)) {
+      if (typeof aWrappedObject[propertyName] == "function") {
+        this[propertyName] = makeForwardingFunction(propertyName);
+      } else {
+        this[propertyName] = aWrappedObject[propertyName];
       }
     }
   }
+}
 
-  MockWindowsRegKey.prototype = {
-    // --- Overridden nsISupports interface functions ---
+MockWindowsRegKey.prototype = {
+  // --- Overridden nsISupports interface functions ---
 
-    QueryInterface: ChromeUtils.generateQI([Ci.nsIWindowsRegKey]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWindowsRegKey]),
 
-    // --- Overridden nsIWindowsRegKey interface functions ---
+  // --- Overridden nsIWindowsRegKey interface functions ---
 
-    open(aRootKey, aRelPath, aMode) {
-      // Remember the provided root key and path
-      this._rootKey = aRootKey;
-      this._relPath = aRelPath;
+  open(aRootKey, aRelPath, aMode) {
+    // Remember the provided root key and path
+    this._rootKey = aRootKey;
+    this._relPath = aRelPath;
 
-      // Create the actual registry key
-      return this._wrappedObject.open(aRootKey, aRelPath, aMode);
-    },
+    // Create the actual registry key
+    return this._wrappedObject.open(aRootKey, aRelPath, aMode);
+  },
+
+  openChild(aRelPath, aMode) {
+    // Open the child key and wrap it
+    var innerKey = this._wrappedObject.openChild(aRelPath, aMode);
+    var key = new MockWindowsRegKey(innerKey);
 
-    openChild(aRelPath, aMode) {
-      // Open the child key and wrap it
-      var innerKey = this._wrappedObject.openChild(aRelPath, aMode);
-      var key = new MockWindowsRegKey(innerKey);
+    // Set the properties of the child key and return it
+    key._rootKey = this._rootKey;
+    key._relPath = this._relPath + aRelPath;
+    return key;
+  },
 
-      // Set the properties of the child key and return it
-      key._rootKey = this._rootKey;
-      key._relPath = this._relPath + aRelPath;
-      return key;
-    },
+  createChild(aRelPath, aMode) {
+    // Create the child key and wrap it
+    var innerKey = this._wrappedObject.createChild(aRelPath, aMode);
+    var key = new MockWindowsRegKey(innerKey);
 
-    createChild(aRelPath, aMode) {
-      // Create the child key and wrap it
-      var innerKey = this._wrappedObject.createChild(aRelPath, aMode);
-      var key = new MockWindowsRegKey(innerKey);
+    // Set the properties of the child key and return it
+    key._rootKey = this._rootKey;
+    key._relPath = this._relPath + aRelPath;
+    return key;
+  },
 
-      // Set the properties of the child key and return it
-      key._rootKey = this._rootKey;
-      key._relPath = this._relPath + aRelPath;
-      return key;
-    },
+  get childCount() {
+    return this._wrappedObject.childCount;
+  },
 
-    get childCount() {
-      return this._wrappedObject.childCount;
-    },
+  get valueCount() {
+    return this._wrappedObject.valueCount;
+  },
 
-    get valueCount() {
-      return this._wrappedObject.valueCount;
-    },
+  readStringValue(aName) {
+    // If this is the key under test, return a fake value
+    if (this._rootKey == Ci.nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT &&
+        this._relPath.toLowerCase() == FILE_EXTENSION &&
+        aName.toLowerCase() == "content type") {
+      gTestUsedOurMock = true;
+      return "";
+    }
+    // Return the real value from the registry
+    return this._wrappedObject.readStringValue(aName);
+  },
+};
 
-    readStringValue(aName) {
-      // If this is the key under test, return a fake value
-      if (this._rootKey == Ci.nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT &&
-          this._relPath.toLowerCase() == ".txt" &&
-          aName.toLowerCase() == "content type") {
-        return "";
+function registerMockWindowsRegKeyFactory() {
+  const kMockCID = Components.ID("{9b23dfe9-296b-4740-ba1c-d39c9a16e55e}");
+  const kWindowsRegKeyContractID = "@mozilla.org/windows-registry-key;1";
+  // Preserve the original CID.
+  let originalWindowsRegKeyCID = Cc[kWindowsRegKeyContractID].number;
+
+  info("Create a mock RegKey factory");
+  let originalRegKey = Cc["@mozilla.org/windows-registry-key;1"]
+                          .createInstance(Ci.nsIWindowsRegKey);
+  let mockWindowsRegKeyFactory = {
+    createInstance(outer, iid) {
+      if (outer != null) {
+        throw Cr.NS_ERROR_NO_AGGREGATION;
       }
-
-      // Return the real value in the registry
-      return this._wrappedObject.readStringValue(aName);
+      info("Create a mock wrapper around RegKey");
+      var key = new MockWindowsRegKey(originalRegKey);
+      return key.QueryInterface(iid);
     },
   };
-
-  // --- Mock nsIWindowsRegKey factory ---
-
-  var componentRegistrar = Components.manager.
-                           QueryInterface(Ci.nsIComponentRegistrar);
-
-  var originalWindowsRegKeyCID;
-  var mockWindowsRegKeyFactory;
-
-  const kMockCID = Components.ID("{9b23dfe9-296b-4740-ba1c-d39c9a16e55e}");
-  const kWindowsRegKeyContractID = "@mozilla.org/windows-registry-key;1";
+  info("Register the mock RegKey factory");
+  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+  registrar.registerFactory(
+    kMockCID,
+    "Mock Windows Registry Key Implementation",
+    kWindowsRegKeyContractID,
+    mockWindowsRegKeyFactory
+  );
 
-  function registerMockWindowsRegKeyFactory() {
-    mockWindowsRegKeyFactory = {
-      createInstance(aOuter, aIid) {
-        if (aOuter != null)
-          throw Cr.NS_ERROR_NO_AGGREGATION;
-        // XXX Bug 1533719 - originalWindowsRegKeyFactory is undefined.
-        // eslint-disable-next-line no-undef
-        var innerKey = originalWindowsRegKeyFactory.createInstance(null, aIid);
-        var key = new MockWindowsRegKey(innerKey);
-
-        return key.QueryInterface(aIid);
-      },
-    };
-
-    // Preserve the original factory
-    originalWindowsRegKeyCID = Cc[kWindowsRegKeyContractID].number;
-
-    // Register the mock factory
-    componentRegistrar.registerFactory(
-      kMockCID,
-      "Mock Windows Registry Key Implementation",
-      kWindowsRegKeyContractID,
-      mockWindowsRegKeyFactory
-    );
-  }
-
-  function unregisterMockWindowsRegKeyFactory() {
+  registerCleanupFunction(() => {
     // Free references to the mock factory
-    componentRegistrar.unregisterFactory(
+    registrar.unregisterFactory(
       kMockCID,
       mockWindowsRegKeyFactory
     );
-
     // Restore the original factory
-    componentRegistrar.registerFactory(
+    registrar.registerFactory(
       Components.ID(originalWindowsRegKeyCID),
       "",
       kWindowsRegKeyContractID,
       null
     );
-  }
-
-  // --- Test procedure ---
-
-  // Activate the override of the ".txt" file association data in the registry
-  registerMockWindowsRegKeyFactory();
-  try {
-    // Try and get the MIME type associated with the extension. If this
-    // operation does not throw an unexpected exception, the test succeeds.
-    Cc["@mozilla.org/mime;1"].
-      getService(Ci.nsIMIMEService).
-      getTypeFromExtension(".txt");
-  } catch (e) {
-    if (!(e instanceof Ci.nsIException) ||
-        e.result != Cr.NS_ERROR_NOT_AVAILABLE) {
-      throw e;
-    }
-    // This is an expected exception, thrown if the type can't be determined
-  } finally {
-    // Ensure we restore the original factory when the test is finished
-    unregisterMockWindowsRegKeyFactory();
-  }
+  });
 }
--- a/uriloader/exthandler/tests/unit/xpcshell.ini
+++ b/uriloader/exthandler/tests/unit/xpcshell.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 head = head.js
 run-sequentially = Bug 912235 - Intermittent failures
 firefox-appdir = browser
 
 [test_getTypeFromExtension_ext_to_type_mapping.js]
 [test_getTypeFromExtension_with_empty_Content_Type.js]
+skip-if = os != "win" # Windows only test
 [test_badMIMEType.js]
 [test_handlerService.js]
 skip-if = (verify && (os == 'win'))
 support-files = mailcap
 # Bug 676997: test consistently fails on Android
 fail-if = os == "android"
 [test_handlerService_store.js]
 support-files = handlers.json