Bug 1915045 Ensure decode tasks are scheduled on BufferingState::Enter() r=media...
[gecko.git] / js / xpconnect / tests / unit / test_xray_instanceof.js
blobd52d06298475dc7ea0917d7c23815aa10dd0cd37
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 add_task(function instanceof_xrays() {
6   let sandbox = Cu.Sandbox(null);
7   Cu.evalInSandbox(`
8     this.proxy = new Proxy([], {
9       getPrototypeOf() {
10         return Date.prototype;
11       },
12     });
14     this.inheritedProxy = Object.create(this.proxy);
16     this.FunctionProxy = new Proxy(function() {}, {});
17     this.functionProxyInstance = new this.FunctionProxy();
19     this.CustomClass = class {};
20     this.customClassInstance = new this.CustomClass();
21   `, sandbox);
23   {
24     // Sanity check that instanceof still works with standard constructors when xrays are present.
25     Assert.ok(Cu.evalInSandbox(`new Date()`, sandbox) instanceof sandbox.Date,
26               "async function result in sandbox instanceof sandbox.Date");
27     Assert.ok(new sandbox.Date() instanceof sandbox.Date,
28               "sandbox.Date() instanceof sandbox.Date");
30     Assert.ok(sandbox.CustomClass instanceof sandbox.Function,
31               "Class constructor instanceof sandbox.Function");
32     Assert.ok(sandbox.CustomClass instanceof sandbox.Object,
33               "Class constructor instanceof sandbox.Object");
35     // Both operands must have the same kind of Xray vision.
36     Assert.equal(Cu.waiveXrays(sandbox.CustomClass) instanceof sandbox.Function, false,
37                  "Class constructor with waived xrays instanceof sandbox.Function");
38     Assert.equal(Cu.waiveXrays(sandbox.CustomClass) instanceof sandbox.Object, false,
39                  "Class constructor with waived xrays instanceof sandbox.Object");
40   }
42   {
43     let {proxy} = sandbox;
44     Assert.equal(proxy instanceof sandbox.Date, false,
45                  "instanceof should ignore the proxy trap");
46     Assert.equal(proxy instanceof sandbox.Array, false,
47                  "instanceof should ignore the proxy target");
48     Assert.equal(Cu.waiveXrays(proxy) instanceof sandbox.Date, false,
49                  "instanceof should ignore the proxy trap despite the waived xrays on the proxy");
50     Assert.equal(Cu.waiveXrays(proxy) instanceof sandbox.Array, false,
51                  "instanceof should ignore the proxy target despite the waived xrays on the proxy");
53     Assert.ok(proxy instanceof Cu.waiveXrays(sandbox.Date),
54               "instanceof should trigger the proxy trap after waiving Xrays on the constructor");
55     Assert.equal(proxy instanceof Cu.waiveXrays(sandbox.Array), false,
56                  "instanceof should trigger the proxy trap after waiving Xrays on the constructor");
58     Assert.ok(Cu.waiveXrays(proxy) instanceof Cu.waiveXrays(sandbox.Date),
59               "instanceof should trigger the proxy trap after waiving both Xrays");
60   }
63   {
64     let {inheritedProxy} = sandbox;
65     Assert.equal(inheritedProxy instanceof sandbox.Date, false,
66                  "instanceof should ignore the inherited proxy trap");
67     Assert.equal(Cu.waiveXrays(inheritedProxy) instanceof sandbox.Date, false,
68                  "instanceof should ignore the inherited proxy trap despite the waived xrays on the proxy");
70     Assert.ok(inheritedProxy instanceof Cu.waiveXrays(sandbox.Date),
71               "instanceof should trigger the inherited proxy trap after waiving Xrays on the constructor");
73     Assert.ok(Cu.waiveXrays(inheritedProxy) instanceof Cu.waiveXrays(sandbox.Date),
74               "instanceof should trigger the inherited proxy trap after waiving both Xrays");
75   }
77   {
78     let {FunctionProxy, functionProxyInstance} = sandbox;
80     // Ideally, the next two test cases should both throw "... not a function".
81     // However, because the opaque XrayWrapper does not override isCallable, an
82     // opaque XrayWrapper is still considered callable if the proxy target is,
83     // and "instanceof" will try to look up the prototype of the wrapper (and
84     // fail because opaque XrayWrappers hide the properties).
85     Assert.throws(
86       () => functionProxyInstance instanceof FunctionProxy,
87       /'prototype' property of FunctionProxy is not an object/,
88       "Opaque constructor proxy should be hidden by Xrays");
89     Assert.throws(
90       () => functionProxyInstance instanceof sandbox.proxy,
91       /sandbox.proxy is not a function/,
92       "Opaque non-constructor proxy should be hidden by Xrays");
94     Assert.ok(functionProxyInstance instanceof Cu.waiveXrays(FunctionProxy),
95               "instanceof should get through the proxy after waiving Xrays on the constructor proxy");
96     Assert.ok(Cu.waiveXrays(functionProxyInstance) instanceof Cu.waiveXrays(FunctionProxy),
97               "instanceof should get through the proxy after waiving both Xrays");
98   }
100   {
101     let {CustomClass, customClassInstance} = sandbox;
102     // Under Xray vision, every JS object is either a plain object or array.
103     // Prototypical inheritance is invisible when the constructor is wrapped.
104     Assert.throws(
105       () => customClassInstance instanceof CustomClass,
106       /TypeError: 'prototype' property of CustomClass is not an object/,
107       "instanceof on a custom JS class with xrays should fail");
108     Assert.ok(customClassInstance instanceof Cu.waiveXrays(CustomClass),
109               "instanceof should see the true prototype of CustomClass after waiving Xrays on the class");
110     Assert.ok(Cu.waiveXrays(customClassInstance) instanceof Cu.waiveXrays(CustomClass),
111               "instanceof should see the true prototype of CustomClass after waiving Xrays");
112   }
115 add_task(function instanceof_dom_xrays_hasInstance() {
116   const principal = Services.scriptSecurityManager.createNullPrincipal({});
117   const webnav = Services.appShell.createWindowlessBrowser(false);
118   webnav.docShell.createAboutBlankDocumentViewer(principal, principal);
119   let window = webnav.document.defaultView;
121   let sandbox = Cu.Sandbox(principal);
122   sandbox.DOMObjectWithHasInstance = window.document;
123   Cu.evalInSandbox(`
124     this.DOMObjectWithHasInstance[Symbol.hasInstance] = function() {
125       return true;
126     };
127     this.ObjectWithHasInstance = {
128       [Symbol.hasInstance](v) {
129         v.throwsIfVCannotBeAccessed;
130         return true;
131       },
132     };
133   `, sandbox);
135   // Override the hasInstance handler in the window, so that we can detect when
136   // we end up triggering hasInstance in the window's compartment.
137   window.eval(`
138     document[Symbol.hasInstance] = function() {
139       throw "hasInstance_in_window";
140     };
141   `);
143   sandbox.domobj = window.document.body;
144   Assert.ok(sandbox.eval(`domobj.wrappedJSObject`),
145             "DOM object is a XrayWrapper");
146   Assert.ok(sandbox.eval(`DOMObjectWithHasInstance.wrappedJSObject`),
147             "DOM object with Symbol.hasInstance is a XrayWrapper");
149   for (let Obj of ["ObjectWithHasInstance", "DOMObjectWithHasInstance"]) {
150     // Tests Xray vision *inside* the sandbox. The Symbol.hasInstance member
151     // is a property / expando object in the sandbox's compartment, so the
152     // "instanceof" operator should always trigger the hasInstance function.
153     Assert.ok(sandbox.eval(`[] instanceof ${Obj}`),
154               `Should call ${Obj}[Symbol.hasInstance] when left operand has no Xrays`);
155     Assert.ok(sandbox.eval(`domobj instanceof ${Obj}`),
156               `Should call ${Obj}[Symbol.hasInstance] when left operand has Xrays`);
157     Assert.ok(sandbox.eval(`domobj.wrappedJSObject instanceof ${Obj}`),
158               `Should call ${Obj}[Symbol.hasInstance] when left operand has waived Xrays`);
160     // Tests Xray vision *outside* the sandbox. The Symbol.hasInstance member
161     // should be hidden by Xrays.
162     let sandboxObjWithHasInstance = sandbox[Obj];
163     Assert.ok(Cu.isXrayWrapper(sandboxObjWithHasInstance),
164               `sandbox.${Obj} is a XrayWrapper`);
165     Assert.throws(
166       () => sandbox.Object() instanceof sandboxObjWithHasInstance,
167       /sandboxObjWithHasInstance is not a function/,
168       `sandbox.${Obj}[Symbol.hasInstance] should be hidden by Xrays`);
170     Assert.throws(
171       () => Cu.waiveXrays(sandbox.Object()) instanceof sandboxObjWithHasInstance,
172       /sandboxObjWithHasInstance is not a function/,
173       `sandbox.${Obj}[Symbol.hasInstance] should be hidden by Xrays, despite the waived Xrays at the left`);
175     // (Cases where the left operand has no Xrays are checked below.)
176   }
178   // hasInstance is expected to be called, but still trigger an error because
179   // properties of the object from the current context should not be readable
180   // by the hasInstance function in the sandbox with a different principal.
181   Assert.throws(
182     () => [] instanceof Cu.waiveXrays(sandbox.ObjectWithHasInstance),
183     /Permission denied to access property "throwsIfVCannotBeAccessed"/,
184     `Should call (waived) sandbox.ObjectWithHasInstance[Symbol.hasInstance] when the right operand has waived Xrays`);
186   // The Xray waiver on the right operand should be sufficient to call
187   // hasInstance even if the left operand still has Xrays.
188   Assert.ok(sandbox.Object() instanceof Cu.waiveXrays(sandbox.ObjectWithHasInstance),
189             `Should call (waived) sandbox.ObjectWithHasInstance[Symbol.hasInstance] when the right operand has waived Xrays`);
190   Assert.ok(Cu.waiveXrays(sandbox.Object()) instanceof Cu.waiveXrays(sandbox.ObjectWithHasInstance),
191             `Should call (waived) sandbox.ObjectWithHasInstance[Symbol.hasInstance] when both operands have waived Xrays`);
193   // When Xrays of the DOM object are waived, we end up in the owner document's
194   // compartment (instead of the sandbox).
195   Assert.throws(
196     () => [] instanceof Cu.waiveXrays(sandbox.DOMObjectWithHasInstance),
197     /hasInstance_in_window/,
198     "Should call (waived) sandbox.DOMObjectWithHasInstance[Symbol.hasInstance] when the right operand has waived Xrays");
200   Assert.throws(
201     () => Cu.waiveXrays(sandbox.Object()) instanceof Cu.waiveXrays(sandbox.DOMObjectWithHasInstance),
202     /hasInstance_in_window/,
203     "Should call (waived) sandbox.DOMObjectWithHasInstance[Symbol.hasInstance] when both operands have waived Xrays");
205   webnav.close();