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/. */
7 var EXPORTED_SYMBOLS = ["MockRegistrar"];
9 const Cm = Components.manager;
11 const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
12 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
13 var logger = Log.repository.getLogger("MockRegistrar");
15 var MockRegistrar = Object.freeze({
16 _registeredComponents: new Map(),
17 _originalCIDs: new Map(),
19 return Cm.QueryInterface(Ci.nsIComponentRegistrar);
23 * Register a mock to override target interfaces.
24 * The target interface may be accessed through _genuine property of the mock.
25 * If you register multiple mocks to the same contract ID, you have to call
26 * unregister in reverse order. Otherwise the previous factory will not be
29 * @param contractID The contract ID of the interface which is overridden by
31 * e.g. "@mozilla.org/file/directory_service;1"
32 * @param mock An object which implements interfaces for the contract ID.
33 * @param args An array which is passed in the constructor of mock.
35 * @return The CID of the mock.
37 register(contractID, mock, args) {
38 let originalCID = this._originalCIDs.get(contractID);
40 originalCID = this.registrar.contractIDToCID(contractID);
41 this._originalCIDs.set(contractID, originalCID);
44 let originalFactory = Cm.getClassObject(originalCID, Ci.nsIFactory);
46 let cid = Services.uuid.generateUUID();
49 createInstance(outer, iid) {
51 throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
55 if (mock.prototype && mock.prototype.constructor) {
56 wrappedMock = Object.create(mock.prototype);
57 mock.apply(wrappedMock, args);
63 let genuine = originalFactory.createInstance(outer, iid);
64 wrappedMock._genuine = genuine;
66 logger.info("Creating original instance failed", ex);
69 return wrappedMock.QueryInterface(iid);
72 throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
74 QueryInterface: ChromeUtils.generateQI(["nsIFactory"]),
77 this.registrar.registerFactory(
79 "A Mock for " + contractID,
84 this._registeredComponents.set(cid, {
94 * Unregister the mock.
96 * @param cid The CID of the mock.
99 let component = this._registeredComponents.get(cid);
104 this.registrar.unregisterFactory(cid, component.factory);
105 if (component.originalCID) {
106 // Passing `null` for the factory re-maps the contract ID to the
107 // entry for its original CID.
108 this.registrar.registerFactory(
109 component.originalCID,
111 component.contractID,
116 this._registeredComponents.delete(cid);
120 * Unregister all registered mocks.
123 for (let cid of this._registeredComponents.keys()) {
124 this.unregister(cid);