tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MockObjects.js (3015B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /**
      6 * Allows registering a mock XPCOM component, that temporarily replaces the
      7 *  original one when an object implementing a given ContractID is requested
      8 *  using createInstance.
      9 *
     10 * @param aContractID
     11 *        The ContractID of the component to replace, for example
     12 *        "@mozilla.org/filepicker;1".
     13 *
     14 * @param aReplacementCtor
     15 *        The constructor function for the JavaScript object that will be
     16 *        created every time createInstance is called. This object must
     17 *        implement QueryInterface and provide the XPCOM interfaces required by
     18 *        the specified ContractID (for example
     19 *        Components.interfaces.nsIFilePicker).
     20 */
     21 
     22 function MockObjectRegisterer(aContractID, aReplacementCtor) {
     23  this._contractID = aContractID;
     24  this._replacementCtor = aReplacementCtor;
     25 }
     26 
     27 MockObjectRegisterer.prototype = {
     28  /**
     29   * Replaces the current factory with one that returns a new mock object.
     30   *
     31   * After register() has been called, it is mandatory to call unregister() to
     32   * restore the original component. Usually, you should use a try-catch block
     33   * to ensure that unregister() is called.
     34   */
     35  register: function MOR_register() {
     36    if (this._originalCID) {
     37      throw new Error("Invalid object state when calling register()");
     38    }
     39 
     40    // Define a factory that creates a new object using the given constructor.
     41    var isChrome = location.protocol == "chrome:";
     42    var providedConstructor = this._replacementCtor;
     43    this._mockFactory = {
     44      createInstance: function MF_createInstance(aIid) {
     45        var inst = new providedConstructor().QueryInterface(aIid);
     46        if (!isChrome) {
     47          inst = SpecialPowers.wrapCallbackObject(inst);
     48        }
     49        return inst;
     50      },
     51    };
     52    if (!isChrome) {
     53      this._mockFactory = SpecialPowers.wrapCallbackObject(this._mockFactory);
     54    }
     55 
     56    var retVal = SpecialPowers.swapFactoryRegistration(
     57      null,
     58      this._contractID,
     59      this._mockFactory
     60    );
     61    if ("error" in retVal) {
     62      throw new Error("ERROR: " + retVal.error);
     63    } else {
     64      this._originalCID = retVal.originalCID;
     65    }
     66  },
     67 
     68  /**
     69   * Restores the original factory.
     70   */
     71  unregister: function MOR_unregister() {
     72    if (!this._originalCID) {
     73      throw new Error("Invalid object state when calling unregister()");
     74    }
     75 
     76    // Free references to the mock factory.
     77    SpecialPowers.swapFactoryRegistration(this._originalCID, this._contractID);
     78 
     79    // Allow registering a mock factory again later.
     80    this._originalCID = null;
     81    this._mockFactory = null;
     82  },
     83 
     84  // --- Private methods and properties ---
     85 
     86  /**
     87   * The factory of the component being replaced.
     88   */
     89  _originalCID: null,
     90 
     91  /**
     92   * The nsIFactory that was automatically generated by this object.
     93   */
     94  _mockFactory: null,
     95 };