summaryrefslogtreecommitdiffstats
path: root/testing/mochitest/tests/SimpleTest/MockObjects.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/mochitest/tests/SimpleTest/MockObjects.js')
-rw-r--r--testing/mochitest/tests/SimpleTest/MockObjects.js95
1 files changed, 95 insertions, 0 deletions
diff --git a/testing/mochitest/tests/SimpleTest/MockObjects.js b/testing/mochitest/tests/SimpleTest/MockObjects.js
new file mode 100644
index 0000000000..5782707c04
--- /dev/null
+++ b/testing/mochitest/tests/SimpleTest/MockObjects.js
@@ -0,0 +1,95 @@
+/* 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._originalCID) {
+ throw new Error("Invalid object state when calling register()");
+ }
+
+ // Define a factory that creates a new object using the given constructor.
+ var isChrome = location.protocol == "chrome:";
+ var providedConstructor = this._replacementCtor;
+ this._mockFactory = {
+ createInstance: function MF_createInstance(aIid) {
+ var inst = new providedConstructor().QueryInterface(aIid);
+ if (!isChrome) {
+ inst = SpecialPowers.wrapCallbackObject(inst);
+ }
+ return inst;
+ },
+ };
+ if (!isChrome) {
+ this._mockFactory = SpecialPowers.wrapCallbackObject(this._mockFactory);
+ }
+
+ var retVal = SpecialPowers.swapFactoryRegistration(
+ null,
+ this._contractID,
+ this._mockFactory
+ );
+ if ("error" in retVal) {
+ throw new Error("ERROR: " + retVal.error);
+ } else {
+ this._originalCID = retVal.originalCID;
+ }
+ },
+
+ /**
+ * Restores the original factory.
+ */
+ unregister: function MOR_unregister() {
+ if (!this._originalCID) {
+ throw new Error("Invalid object state when calling unregister()");
+ }
+
+ // Free references to the mock factory.
+ SpecialPowers.swapFactoryRegistration(this._originalCID, this._contractID);
+
+ // Allow registering a mock factory again later.
+ this._originalCID = null;
+ this._mockFactory = null;
+ },
+
+ // --- Private methods and properties ---
+
+ /**
+ * The factory of the component being replaced.
+ */
+ _originalCID: null,
+
+ /**
+ * The nsIFactory that was automatically generated by this object.
+ */
+ _mockFactory: null,
+};