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 };