michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: const { sandbox, load, evaluate, nuke } = require('sdk/loader/sandbox'); michael@0: const xulApp = require("sdk/system/xul-app"); michael@0: const fixturesURI = module.uri.split('test-sandbox.js')[0] + 'fixtures/'; michael@0: michael@0: // The following adds Debugger constructor to the global namespace. michael@0: const { Cu } = require('chrome'); michael@0: const { addDebuggerToGlobal } = michael@0: Cu.import('resource://gre/modules/jsdebugger.jsm', {}); michael@0: addDebuggerToGlobal(this); michael@0: michael@0: exports['test basics'] = function(assert) { michael@0: let fixture = sandbox('http://example.com'); michael@0: assert.equal(evaluate(fixture, 'var a = 1;'), undefined, michael@0: 'returns expression value'); michael@0: assert.equal(evaluate(fixture, 'b = 2;'), 2, michael@0: 'returns expression value'); michael@0: assert.equal(fixture.b, 2, 'global is defined as property'); michael@0: assert.equal(fixture.a, 1, 'global is defined as property'); michael@0: assert.equal(evaluate(fixture, 'a + b;'), 3, 'returns correct sum'); michael@0: }; michael@0: michael@0: exports['test non-privileged'] = function(assert) { michael@0: let fixture = sandbox('http://example.com'); michael@0: if (xulApp.versionInRange(xulApp.platformVersion, "15.0a1", "18.*")) { michael@0: let rv = evaluate(fixture, 'Compo' + 'nents.utils'); michael@0: assert.equal(rv, undefined, michael@0: "Components's attributes are undefined in content sandboxes"); michael@0: } michael@0: else { michael@0: assert.throws(function() { michael@0: evaluate(fixture, 'Compo' + 'nents.utils'); michael@0: }, 'Access to components is restricted'); michael@0: } michael@0: fixture.sandbox = sandbox; michael@0: assert.throws(function() { michael@0: evaluate(fixture, sandbox('http://foo.com')); michael@0: }, 'Can not call privileged code'); michael@0: }; michael@0: michael@0: exports['test injection'] = function(assert) { michael@0: let fixture = sandbox(); michael@0: fixture.hi = function(name) 'Hi ' + name michael@0: assert.equal(evaluate(fixture, 'hi("sandbox");'), 'Hi sandbox', michael@0: 'injected functions are callable'); michael@0: }; michael@0: michael@0: exports['test exceptions'] = function(assert) { michael@0: let fixture = sandbox(); michael@0: try { michael@0: evaluate(fixture, '!' + function() { michael@0: var message = 'boom'; michael@0: throw Error(message); michael@0: } + '();'); michael@0: } michael@0: catch (error) { michael@0: assert.equal(error.fileName, '', 'no fileName reported'); michael@0: assert.equal(error.lineNumber, 3, 'reports correct line number'); michael@0: } michael@0: michael@0: try { michael@0: evaluate(fixture, '!' + function() { michael@0: var message = 'boom'; michael@0: throw Error(message); michael@0: } + '();', 'foo.js'); michael@0: } michael@0: catch (error) { michael@0: assert.equal(error.fileName, 'foo.js', 'correct fileName reported'); michael@0: assert.equal(error.lineNumber, 3, 'reports correct line number'); michael@0: } michael@0: michael@0: try { michael@0: evaluate(fixture, '!' + function() { michael@0: var message = 'boom'; michael@0: throw Error(message); michael@0: } + '();', 'foo.js', 2); michael@0: } michael@0: catch (error) { michael@0: assert.equal(error.fileName, 'foo.js', 'correct fileName reported'); michael@0: assert.equal(error.lineNumber, 4, 'line number was opted'); michael@0: } michael@0: }; michael@0: michael@0: exports['test opt version'] = function(assert) { michael@0: let fixture = sandbox(); michael@0: assert.throws(function() { michael@0: evaluate(fixture, 'let a = 2;', 'test.js', 1, '1.5'); michael@0: }, 'No let in js 1.5'); michael@0: }; michael@0: michael@0: exports['test load'] = function(assert) { michael@0: let fixture = sandbox(); michael@0: load(fixture, fixturesURI + 'sandbox-normal.js'); michael@0: assert.equal(fixture.a, 1, 'global variable defined'); michael@0: assert.equal(fixture.b, 2, 'global via `this` property was set'); michael@0: assert.equal(fixture.f(), 4, 'function was defined'); michael@0: }; michael@0: michael@0: exports['test load with data: URL'] = function(assert) { michael@0: let code = "var a = 1; this.b = 2; function f() 4"; michael@0: let fixture = sandbox(); michael@0: load(fixture, "data:," + encodeURIComponent(code)); michael@0: michael@0: assert.equal(fixture.a, 1, 'global variable defined'); michael@0: assert.equal(fixture.b, 2, 'global via `this` property was set'); michael@0: assert.equal(fixture.f(), 4, 'function was defined'); michael@0: }; michael@0: michael@0: exports['test load script with complex char'] = function(assert) { michael@0: let fixture = sandbox(); michael@0: load(fixture, fixturesURI + 'sandbox-complex-character.js'); michael@0: assert.equal(fixture.chars, 'გამარჯობა', 'complex chars were loaded correctly'); michael@0: }; michael@0: michael@0: exports['test load script with data: URL and complex char'] = function(assert) { michael@0: let code = "var chars = 'გამარჯობა';"; michael@0: let fixture = sandbox(); michael@0: load(fixture, "data:," + encodeURIComponent(code)); michael@0: michael@0: assert.equal(fixture.chars, 'გამარჯობა', 'complex chars were loaded correctly'); michael@0: }; michael@0: michael@0: exports['test metadata'] = function(assert) { michael@0: let dbg = new Debugger(); michael@0: dbg.onNewGlobalObject = function(global) { michael@0: let metadata = Cu.getSandboxMetadata(global.unsafeDereference()); michael@0: assert.ok(metadata, 'this global has attached metadata'); michael@0: assert.equal(metadata.addonID, self.id, 'addon ID is set'); michael@0: michael@0: dbg.onNewGlobalObject = undefined; michael@0: } michael@0: michael@0: let fixture = sandbox(); michael@0: let self = require('sdk/self'); michael@0: } michael@0: michael@0: exports['test nuke sandbox'] = function(assert) { michael@0: michael@0: let fixture = sandbox('http://example.com'); michael@0: fixture.foo = 'foo'; michael@0: michael@0: let ref = evaluate(fixture, 'let a = {bar: "bar"}; a'); michael@0: michael@0: nuke(fixture); michael@0: michael@0: assert.ok(Cu.isDeadWrapper(fixture), 'sandbox should be dead'); michael@0: michael@0: assert.throws( michael@0: () => fixture.foo, michael@0: /can't access dead object/, michael@0: 'property of nuked sandbox should not be accessible' michael@0: ); michael@0: michael@0: assert.ok(Cu.isDeadWrapper(ref), 'ref to object from sandbox should be dead'); michael@0: michael@0: assert.throws( michael@0: () => ref.bar, michael@0: /can't access dead object/, michael@0: 'object from nuked sandbox should not be alive' michael@0: ); michael@0: } michael@0: michael@0: require('test').run(exports);