summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/tests/unit/test_interposition.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/xpconnect/tests/unit/test_interposition.js')
-rw-r--r--js/xpconnect/tests/unit/test_interposition.js165
1 files changed, 165 insertions, 0 deletions
diff --git a/js/xpconnect/tests/unit/test_interposition.js b/js/xpconnect/tests/unit/test_interposition.js
new file mode 100644
index 000000000..f755bbd7d
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_interposition.js
@@ -0,0 +1,165 @@
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const ADDONID = "bogus-addon@mozilla.org";
+
+let gExpectedProp;
+function expectAccess(prop, f)
+{
+ gExpectedProp = prop;
+ f();
+ do_check_eq(gExpectedProp, undefined);
+}
+
+let getter_run = false;
+function test_getter()
+{
+ do_check_eq(getter_run, false);
+ getter_run = true;
+ return 200;
+}
+
+let setter_run = false;
+function test_setter(v)
+{
+ do_check_eq(setter_run, false);
+ do_check_eq(v, 300);
+ setter_run = true;
+}
+
+let TestInterposition = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonInterposition,
+ Ci.nsISupportsWeakReference]),
+
+ getWhitelist: function() {
+ return ["abcxyz", "utils", "dataprop", "getterprop", "setterprop",
+ "objprop", "defineprop", "configurableprop"];
+ },
+
+ interposeProperty: function(addonId, target, iid, prop) {
+ do_check_eq(addonId, ADDONID);
+ do_check_eq(gExpectedProp, prop);
+ gExpectedProp = undefined;
+
+ if (prop == "dataprop") {
+ return { configurable: false, enumerable: true, writable: false, value: 100 };
+ } else if (prop == "getterprop") {
+ return { configurable: false, enumerable: true, get: test_getter };
+ } else if (prop == "setterprop") {
+ return { configurable: false, enumerable: true, get: test_getter, set: test_setter };
+ } else if (prop == "utils") {
+ do_check_eq(iid, Ci.nsIXPCComponents.number);
+ return null;
+ } else if (prop == "objprop") {
+ gExpectedProp = "objprop"; // allow recursive access here
+ return { configurable: false, enumerable: true, writable: false, value: { objprop: 1 } };
+ } else if (prop == "configurableprop") {
+ return { configurable: true, enumerable: true, writable: false, value: 10 };
+ }
+
+ return null;
+ },
+
+ interposeCall: function(addonId, originalFunc, originalThis, args) {
+ do_check_eq(addonId, ADDONID);
+ args.splice(0, 0, addonId);
+ return originalFunc.apply(originalThis, args);
+ }
+};
+
+function run_test()
+{
+ Cu.setAddonInterposition(ADDONID, TestInterposition);
+
+ Cu.importGlobalProperties(["XMLHttpRequest"]);
+
+ let sandbox = Cu.Sandbox(this, {addonId: ADDONID});
+ sandbox.outerObj = new XMLHttpRequest();
+
+ expectAccess("abcxyz", () => {
+ Cu.evalInSandbox("outerObj.abcxyz = 12;", sandbox);
+ });
+
+ expectAccess("utils", () => {
+ Cu.evalInSandbox("Components.utils;", sandbox);
+ });
+
+ expectAccess("dataprop", () => {
+ do_check_eq(Cu.evalInSandbox("outerObj.dataprop;", sandbox), 100);
+ });
+
+ expectAccess("dataprop", () => {
+ try {
+ Cu.evalInSandbox("'use strict'; outerObj.dataprop = 400;", sandbox);
+ do_check_true(false); // it should throw
+ } catch (e) {}
+ });
+
+ expectAccess("objprop", () => {
+ Cu.evalInSandbox("outerObj.objprop.objprop;", sandbox);
+ gExpectedProp = undefined;
+ });
+
+ expectAccess("getterprop", () => {
+ do_check_eq(Cu.evalInSandbox("outerObj.getterprop;", sandbox), 200);
+ do_check_eq(getter_run, true);
+ getter_run = false;
+ });
+
+ expectAccess("getterprop", () => {
+ try {
+ Cu.evalInSandbox("'use strict'; outerObj.getterprop = 400;", sandbox);
+ do_check_true(false); // it should throw
+ } catch (e) {}
+ do_check_eq(getter_run, false);
+ });
+
+ expectAccess("setterprop", () => {
+ do_check_eq(Cu.evalInSandbox("outerObj.setterprop;", sandbox), 200);
+ do_check_eq(getter_run, true);
+ getter_run = false;
+ do_check_eq(setter_run, false);
+ });
+
+ expectAccess("setterprop", () => {
+ Cu.evalInSandbox("'use strict'; outerObj.setterprop = 300;", sandbox);
+ do_check_eq(getter_run, false);
+ do_check_eq(setter_run, true);
+ setter_run = false;
+ });
+
+ // Make sure that calling Object.defineProperty succeeds as long as
+ // we're not interposing on that property.
+ expectAccess("defineprop", () => {
+ Cu.evalInSandbox("'use strict'; Object.defineProperty(outerObj, 'defineprop', {configurable:true, enumerable:true, writable:true, value:10});", sandbox);
+ });
+
+ // Related to above: make sure we can delete those properties too.
+ expectAccess("defineprop", () => {
+ Cu.evalInSandbox("'use strict'; delete outerObj.defineprop;", sandbox);
+ });
+
+ // Make sure we get configurable=false even if the interposition
+ // sets it to true.
+ expectAccess("configurableprop", () => {
+ let desc = Cu.evalInSandbox("Object.getOwnPropertyDescriptor(outerObj, 'configurableprop')", sandbox);
+ do_check_eq(desc.configurable, false);
+ });
+
+ let moduleScope = Cu.Sandbox(this);
+ moduleScope.ADDONID = ADDONID;
+ moduleScope.do_check_eq = do_check_eq;
+ function funToIntercept(addonId) {
+ do_check_eq(addonId, ADDONID);
+ counter++;
+ }
+ sandbox.moduleFunction = Cu.evalInSandbox(funToIntercept.toSource() + "; funToIntercept", moduleScope);
+ Cu.evalInSandbox("var counter = 0;", moduleScope);
+ Cu.evalInSandbox("Components.utils.setAddonCallInterposition(this);", moduleScope);
+ Cu.evalInSandbox("moduleFunction()", sandbox);
+ do_check_eq(Cu.evalInSandbox("counter", moduleScope), 1);
+ Cu.setAddonInterposition(ADDONID, null);
+}