diff options
Diffstat (limited to 'testing/mochitest/tests/SimpleTest/MockObjects.js')
-rw-r--r-- | testing/mochitest/tests/SimpleTest/MockObjects.js | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/testing/mochitest/tests/SimpleTest/MockObjects.js b/testing/mochitest/tests/SimpleTest/MockObjects.js new file mode 100644 index 000000000..d00f5127b --- /dev/null +++ b/testing/mochitest/tests/SimpleTest/MockObjects.js @@ -0,0 +1,90 @@ +/* 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/. */ + +/** + * Allows registering a mock XPCOM component, that temporarily replaces the + * original one when an object implementing a given ContractID is requested + * using createInstance. + * + * @param aContractID + * The ContractID of the component to replace, for example + * "@mozilla.org/filepicker;1". + * + * @param aReplacementCtor + * The constructor function for the JavaScript object that will be + * created every time createInstance is called. This object must + * implement QueryInterface and provide the XPCOM interfaces required by + * the specified ContractID (for example + * Components.interfaces.nsIFilePicker). + */ + +function MockObjectRegisterer(aContractID, aReplacementCtor) { + this._contractID = aContractID; + this._replacementCtor = aReplacementCtor; +} + +MockObjectRegisterer.prototype = { + /** + * Replaces the current factory with one that returns a new mock object. + * + * After register() has been called, it is mandatory to call unregister() to + * restore the original component. Usually, you should use a try-catch block + * to ensure that unregister() is called. + */ + register: function MOR_register() { + if (this._originalFactory) + throw new Exception("Invalid object state when calling register()"); + + // Define a factory that creates a new object using the given constructor. + var providedConstructor = this._replacementCtor; + this._mockFactory = { + createInstance: function MF_createInstance(aOuter, aIid) { + if (aOuter != null) + throw SpecialPowers.Cr.NS_ERROR_NO_AGGREGATION; + return new providedConstructor().QueryInterface(aIid); + } + }; + + var retVal = SpecialPowers.swapFactoryRegistration(this._cid, this._contractID, this._mockFactory, this._originalFactory); + if ('error' in retVal) { + throw new Exception("ERROR: " + retVal.error); + } else { + this._cid = retVal.cid; + this._originalFactory = retVal.originalFactory; + } + }, + + /** + * Restores the original factory. + */ + unregister: function MOR_unregister() { + if (!this._originalFactory) + throw new Exception("Invalid object state when calling unregister()"); + + // Free references to the mock factory. + SpecialPowers.swapFactoryRegistration(this._cid, this._contractID, this._mockFactory, this._originalFactory); + + // Allow registering a mock factory again later. + this._cid = null; + this._originalFactory = null; + this._mockFactory = null; + }, + + // --- Private methods and properties --- + + /** + * The factory of the component being replaced. + */ + _originalFactory: null, + + /** + * The CID under which the mock contractID was registered. + */ + _cid: null, + + /** + * The nsIFactory that was automatically generated by this object. + */ + _mockFactory: null +} |