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/. */
5 const Cm = Components.manager;
7 export var MockRegistrar = Object.freeze({
8 _registeredComponents: new Map(),
9 _originalCIDs: new Map(),
11 return Cm.QueryInterface(Ci.nsIComponentRegistrar);
15 * Register a mock to override target interfaces.
16 * The target interface may be accessed through _genuine property of the mock.
17 * If you register multiple mocks to the same contract ID, you have to call
18 * unregister in reverse order. Otherwise the previous factory will not be
21 * @param contractID The contract ID of the interface which is overridden by
23 * e.g. "@mozilla.org/file/directory_service;1"
24 * @param mock An object which implements interfaces for the contract ID.
25 * @param args An array which is passed in the constructor of mock.
27 * @return The CID of the mock.
29 register(contractID, mock, args) {
33 originalCID = this._originalCIDs.get(contractID);
35 originalCID = this.registrar.contractIDToCID(contractID);
36 this._originalCIDs.set(contractID, originalCID);
39 originalFactory = Cm.getClassObject(originalCID, Ci.nsIFactory);
41 // There's no original factory. Ignore and just register the new
45 let cid = Services.uuid.generateUUID();
50 if (mock.prototype && mock.prototype.constructor) {
51 wrappedMock = Object.create(mock.prototype);
52 mock.apply(wrappedMock, args);
53 } else if (typeof mock == "function") {
59 if (originalFactory) {
61 let genuine = originalFactory.createInstance(iid);
62 wrappedMock._genuine = genuine;
65 "MockRegistrar: Creating original instance failed",
71 return wrappedMock.QueryInterface(iid);
73 QueryInterface: ChromeUtils.generateQI(["nsIFactory"]),
76 this.registrar.registerFactory(
78 "A Mock for " + contractID,
83 this._registeredComponents.set(cid, {
93 * Unregister the mock.
95 * @param cid The CID of the mock.
98 let component = this._registeredComponents.get(cid);
103 this.registrar.unregisterFactory(cid, component.factory);
104 if (component.originalCID) {
105 // Passing `null` for the factory re-maps the contract ID to the
106 // entry for its original CID.
107 this.registrar.registerFactory(
108 component.originalCID,
110 component.contractID,
115 this._registeredComponents.delete(cid);
119 * Unregister all registered mocks.
122 for (let cid of this._registeredComponents.keys()) {
123 this.unregister(cid);