SpecialPowersSandbox.sys.mjs (3546B)
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 * This modules handles creating and provisioning Sandboxes for 7 * executing cross-process code from SpecialPowers. This allows all such 8 * sandboxes to have a similar environment, and in particular allows 9 * them to run test assertions in the target process and propagate 10 * results back to the caller. 11 */ 12 13 const lazy = {}; 14 15 ChromeUtils.defineESModuleGetters(lazy, { 16 Assert: "resource://testing-common/Assert.sys.mjs", 17 }); 18 19 // Note: When updating the set of globals exposed to sandboxes by 20 // default, please also update the ESLint plugin rule defined in 21 // import-content-task-globals.js. 22 const SANDBOX_GLOBALS = [ 23 "Blob", 24 "ChromeUtils", 25 "FileReader", 26 "TextDecoder", 27 "TextEncoder", 28 "URL", 29 ]; 30 const EXTRA_IMPORTS = { 31 EventUtils: "resource://testing-common/SpecialPowersEventUtils.sys.mjs", 32 }; 33 34 let expectFail = false; 35 function expectingFail(fn) { 36 try { 37 expectFail = true; 38 fn(); 39 } finally { 40 expectFail = false; 41 } 42 } 43 44 export class SpecialPowersSandbox { 45 constructor(name, reportCallback, opts = {}) { 46 this.name = name; 47 this.reportCallback = reportCallback; 48 49 this._Assert = null; 50 51 this.sandbox = Cu.Sandbox( 52 Cu.getGlobalForObject({}), 53 Object.assign( 54 { wantGlobalProperties: SANDBOX_GLOBALS }, 55 opts.sandboxOptions 56 ) 57 ); 58 59 for (let prop of ["assert", "Assert"]) { 60 Object.defineProperty(this.sandbox, prop, { 61 get: () => { 62 return this.Assert; 63 }, 64 enumerable: true, 65 configurable: true, 66 }); 67 } 68 69 let imports = { 70 ...EXTRA_IMPORTS, 71 ...opts.imports, 72 }; 73 // We explicitly want these directly in the sandbox, and we aren't going 74 // to be using the globals within this file. 75 // eslint-disable-next-line mozilla/lazy-getter-object-name 76 ChromeUtils.defineESModuleGetters(this.sandbox, imports); 77 78 // Note: When updating the set of globals exposed to sandboxes by 79 // default, please also update the ESLint plugin rule defined in 80 // import-content-task-globals.js. 81 Object.assign(this.sandbox, { 82 BrowsingContext, 83 InspectorUtils, 84 ok: (...args) => { 85 this.Assert.ok(...args); 86 }, 87 is: (...args) => { 88 this.Assert.equal(...args); 89 }, 90 isnot: (...args) => { 91 this.Assert.notEqual(...args); 92 }, 93 todo: (...args) => { 94 expectingFail(() => this.Assert.ok(...args)); 95 }, 96 todo_is: (...args) => { 97 expectingFail(() => this.Assert.equal(...args)); 98 }, 99 info: info => { 100 this.reportCallback({ info }); 101 }, 102 }); 103 } 104 105 get Assert() { 106 if (!this._Assert) { 107 this._Assert = new lazy.Assert((err, message, stack) => { 108 this.report(err, message, stack); 109 }); 110 } 111 return this._Assert; 112 } 113 114 report(err, name, stack) { 115 let diag; 116 if (err) { 117 diag = 118 `got ${uneval(err.actual)}, expected ${uneval(err.expected)} ` + 119 `(operator ${err.operator})`; 120 } 121 122 this.reportCallback({ 123 name, 124 diag, 125 passed: !err, 126 stack: stack && stack.formattedStack, 127 expectFail, 128 }); 129 } 130 131 execute(task, args, caller) { 132 let func = Cu.evalInSandbox( 133 `(${task})`, 134 this.sandbox, 135 undefined, 136 caller.filename, 137 caller.lineNumber 138 ); 139 return func(...args); 140 } 141 }