testing/modules/AppInfo.jsm
author Nika Layzell <nika@thelayzells.com>
Fri, 20 Jul 2018 18:53:40 -0400
changeset 446904 3439b17bdc2a1bf5626355d529c9a3decf3843be
parent 446900 c019316fcfd49d74775c9b458b3d611f8081ee7e
child 481418 51c89fcec893529391427e14709a2d1bc9c2a962
permissions -rw-r--r--
Bug 1477432 - Part 9: Switch to using plain JS objects for nsIJS[IC]ID, r=mccr8 This is a complete rewrite of the interface while maintaining the same APIs. Each ID is fully-contained within a single object, does not require a finalizer, and is cheap to create. Beyond using reserved slots, this code avoids using custom ClassOps, instead preferring Symbol.hasInstance and eager constants. One major change which occurred in this patch was the move from storing a nsCID to storing the ContractID for JSCID objects. This eliminates the need for the 'refreshCID' method, and hopefully shouldn't have performance implications. If we discover that there are performance problems there, we can look into stashing the CID, and re-introduce 'refreshCID', despite its surprising behaviour. Differential Revision: https://phabricator.services.mozilla.com/D2286

/* This Source Code Form is subject to the terms of the Mozilla Public
 * 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/. */

"use strict";

var EXPORTED_SYMBOLS = [
  "newAppInfo",
  "getAppInfo",
  "updateAppInfo",
];


let origPlatformInfo = Cc["@mozilla.org/xre/app-info;1"]
    .getService(Ci.nsIPlatformInfo);

// eslint-disable-next-line mozilla/use-services
let origRuntime = Cc["@mozilla.org/xre/app-info;1"]
    .getService(Ci.nsIXULRuntime);

/**
 * Create new XULAppInfo instance with specified options.
 *
 * options is a object with following keys:
 *   ID:              nsIXULAppInfo.ID
 *   name:            nsIXULAppInfo.name
 *   version:         nsIXULAppInfo.version
 *   platformVersion: nsIXULAppInfo.platformVersion
 *   OS:              nsIXULRuntime.OS
 *
 *   crashReporter:   nsICrashReporter interface is implemented if true
 *   extraProps:      extra properties added to XULAppInfo
 */
var newAppInfo = function(options = {}) {
  let ID = ("ID" in options) ? options.ID : "xpcshell@tests.mozilla.org";
  let name = ("name" in options) ? options.name : "xpcshell";
  let version = ("version" in options) ? options.version : "1";
  let platformVersion
      = ("platformVersion" in options) ? options.platformVersion : "p-ver";
  let OS = ("OS" in options) ? options.OS : "XPCShell";
  let extraProps = ("extraProps" in options) ? options.extraProps : {};

  let appInfo = {
    // nsIXULAppInfo
    vendor: "Mozilla",
    name,
    ID,
    version,
    appBuildID: "20160315",

    // nsIPlatformInfo
    platformVersion,
    platformBuildID: origPlatformInfo.platformBuildID,

    // nsIXULRuntime
    inSafeMode: false,
    logConsoleErrors: true,
    OS,
    XPCOMABI: "noarch-spidermonkey",
    invalidateCachesOnRestart() {},
    shouldBlockIncompatJaws: false,
    processType: origRuntime.processType,
    uniqueProcessID: origRuntime.uniqueProcessID,

    // nsIWinAppHelper
    get userCanElevate() {
      return false;
    },
  };

  let interfaces = [Ci.nsIXULAppInfo,
                    Ci.nsIPlatformInfo,
                    Ci.nsIXULRuntime];
  if ("nsIWinAppHelper" in Ci) {
    interfaces.push(Ci.nsIWinAppHelper);
  }

  if ("crashReporter" in options && options.crashReporter) {
    // nsICrashReporter
    appInfo.annotations = {};
    appInfo.annotateCrashReport = function(key, data) {
      this.annotations[key] = data;
    };
    interfaces.push(Ci.nsICrashReporter);
  }

  for (let key of Object.keys(extraProps)) {
    appInfo.browserTabsRemoteAutostart = extraProps[key];
  }

  appInfo.QueryInterface = ChromeUtils.generateQI(interfaces);

  return appInfo;
};

var currentAppInfo = newAppInfo();

/**
 * Obtain a reference to the current object used to define XULAppInfo.
 */
var getAppInfo = function() { return currentAppInfo; };

/**
 * Update the current application info.
 *
 * See newAppInfo for options.
 *
 * To change the current XULAppInfo, simply call this function. If there was
 * a previously registered app info object, it will be unloaded and replaced.
 */
var updateAppInfo = function(options) {
  currentAppInfo = newAppInfo(options);

  let id = Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}");
  let contractid = "@mozilla.org/xre/app-info;1";
  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);

  // Unregister an existing factory if one exists.
  try {
    let existing = Components.manager.getClassObjectByContractID(contractid, Ci.nsIFactory);
    registrar.unregisterFactory(id, existing);
  } catch (ex) {}

  let factory = {
    createInstance(outer, iid) {
      if (outer != null) {
        throw Cr.NS_ERROR_NO_AGGREGATION;
      }

      return currentAppInfo.QueryInterface(iid);
    },
  };

  registrar.registerFactory(id, "XULAppInfo", contractid, factory);
};