addon-sdk/source/test/test-loader.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/addon-sdk/source/test/test-loader.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,346 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +'use strict';
     1.9 +
    1.10 +let {
    1.11 +  Loader, main, unload, parseStack, generateMap, resolve, join
    1.12 +} = require('toolkit/loader');
    1.13 +let { readURI } = require('sdk/net/url');
    1.14 +
    1.15 +let root = module.uri.substr(0, module.uri.lastIndexOf('/'))
    1.16 +
    1.17 +
    1.18 +// The following adds Debugger constructor to the global namespace.
    1.19 +const { Cu } = require('chrome');
    1.20 +const { addDebuggerToGlobal } = Cu.import('resource://gre/modules/jsdebugger.jsm', {});
    1.21 +addDebuggerToGlobal(this);
    1.22 +
    1.23 +exports['test resolve'] = function (assert) {
    1.24 +  let cuddlefish_id = 'sdk/loader/cuddlefish';
    1.25 +  assert.equal(resolve('../index.js', './dir/c.js'), './index.js');
    1.26 +  assert.equal(resolve('./index.js', './dir/c.js'), './dir/index.js');
    1.27 +  assert.equal(resolve('./dir/c.js', './index.js'), './dir/c.js');
    1.28 +  assert.equal(resolve('../utils/file.js', './dir/b.js'), './utils/file.js');
    1.29 +
    1.30 +  assert.equal(resolve('../utils/./file.js', './dir/b.js'), './utils/file.js');
    1.31 +  assert.equal(resolve('../utils/file.js', './'), './../utils/file.js');
    1.32 +  assert.equal(resolve('./utils/file.js', './'), './utils/file.js');
    1.33 +  assert.equal(resolve('./utils/file.js', './index.js'), './utils/file.js');
    1.34 +
    1.35 +  assert.equal(resolve('../utils/./file.js', cuddlefish_id), 'sdk/utils/file.js');
    1.36 +  assert.equal(resolve('../utils/file.js', cuddlefish_id), 'sdk/utils/file.js');
    1.37 +  assert.equal(resolve('./utils/file.js', cuddlefish_id), 'sdk/loader/utils/file.js');
    1.38 +
    1.39 +  assert.equal(resolve('..//index.js', './dir/c.js'), './index.js');
    1.40 +  assert.equal(resolve('../../gre/modules/XPCOMUtils.jsm', 'resource://thing/utils/file.js'), 'resource://gre/modules/XPCOMUtils.jsm');
    1.41 +  assert.equal(resolve('../../gre/modules/XPCOMUtils.jsm', 'chrome://thing/utils/file.js'), 'chrome://gre/modules/XPCOMUtils.jsm');
    1.42 +  assert.equal(resolve('../../a/b/c.json', 'file:///thing/utils/file.js'), 'file:///a/b/c.json');
    1.43 +
    1.44 +  // Does not change absolute paths
    1.45 +  assert.equal(resolve('resource://gre/modules/file.js', './dir/b.js'),
    1.46 +    'resource://gre/modules/file.js');
    1.47 +  assert.equal(resolve('file:///gre/modules/file.js', './dir/b.js'),
    1.48 +    'file:///gre/modules/file.js');
    1.49 +  assert.equal(resolve('/root.js', './dir/b.js'),
    1.50 +    '/root.js');
    1.51 +};
    1.52 +
    1.53 +exports['test join'] = function (assert) {
    1.54 +  assert.equal(join('a/path', '../../../module'), '../module');
    1.55 +  assert.equal(join('a/path/to', '../module'), 'a/path/module');
    1.56 +  assert.equal(join('a/path/to', './module'), 'a/path/to/module');
    1.57 +  assert.equal(join('a/path/to', '././../module'), 'a/path/module');
    1.58 +  assert.equal(join('resource://my/path/yeah/yuh', '../whoa'),
    1.59 +    'resource://my/path/yeah/whoa');
    1.60 +  assert.equal(join('resource://my/path/yeah/yuh', './whoa'),
    1.61 +    'resource://my/path/yeah/yuh/whoa');
    1.62 +  assert.equal(join('file:///my/path/yeah/yuh', '../whoa'),
    1.63 +    'file:///my/path/yeah/whoa');
    1.64 +  assert.equal(join('file:///my/path/yeah/yuh', './whoa'),
    1.65 +    'file:///my/path/yeah/yuh/whoa');
    1.66 +  assert.equal(join('a/path/to', '..//module'), 'a/path/module');
    1.67 +};
    1.68 +
    1.69 +exports['test dependency cycles'] = function(assert) {
    1.70 +  let uri = root + '/fixtures/loader/cycles/';
    1.71 +  let loader = Loader({ paths: { '': uri } });
    1.72 +
    1.73 +  let program = main(loader, 'main');
    1.74 +
    1.75 +  assert.equal(program.a.b, program.b, 'module `a` gets correct `b`');
    1.76 +  assert.equal(program.b.a, program.a, 'module `b` gets correct `a`');
    1.77 +  assert.equal(program.c.main, program, 'module `c` gets correct `main`');
    1.78 +
    1.79 +  unload(loader);
    1.80 +}
    1.81 +
    1.82 +exports['test syntax errors'] = function(assert) {
    1.83 +  let uri = root + '/fixtures/loader/syntax-error/';
    1.84 +  let loader = Loader({ paths: { '': uri } });
    1.85 +
    1.86 +  try {
    1.87 +    let program = main(loader, 'main');
    1.88 +  } catch (error) {
    1.89 +    assert.equal(error.name, "SyntaxError", "throws syntax error");
    1.90 +    assert.equal(error.fileName.split("/").pop(), "error.js",
    1.91 +              "Error contains filename");
    1.92 +    assert.equal(error.lineNumber, 11, "error is on line 11");
    1.93 +    let stack = parseStack(error.stack);
    1.94 +
    1.95 +    assert.equal(stack.pop().fileName, uri + "error.js",
    1.96 +                 "last frame file containing syntax error");
    1.97 +    assert.equal(stack.pop().fileName, uri + "main.js",
    1.98 +                 "previous frame is a requirer module");
    1.99 +    assert.equal(stack.pop().fileName, module.uri,
   1.100 +                 "previous to it is a test module");
   1.101 +
   1.102 +  } finally {
   1.103 +    unload(loader);
   1.104 +  }
   1.105 +}
   1.106 +
   1.107 +exports['test sandboxes are not added if error'] = function (assert) {
   1.108 +  let uri = root + '/fixtures/loader/missing-twice/';
   1.109 +  let loader = Loader({ paths: { '': uri } });
   1.110 +  let program = main(loader, 'main');
   1.111 +  assert.ok(!(uri + 'not-found.js' in loader.sandboxes), 'not-found.js not in loader.sandboxes');
   1.112 +}
   1.113 +
   1.114 +exports['test missing module'] = function(assert) {
   1.115 +  let uri = root + '/fixtures/loader/missing/'
   1.116 +  let loader = Loader({ paths: { '': uri } });
   1.117 +
   1.118 +  try {
   1.119 +    let program = main(loader, 'main')
   1.120 +  } catch (error) {
   1.121 +    assert.equal(error.message, "Module `not-found` is not found at " +
   1.122 +                uri + "not-found.js", "throws if error not found");
   1.123 +
   1.124 +    assert.equal(error.fileName.split("/").pop(), "main.js",
   1.125 +                 "Error fileName is requirer module");
   1.126 +
   1.127 +    assert.equal(error.lineNumber, 7, "error is on line 7");
   1.128 +
   1.129 +    let stack = parseStack(error.stack);
   1.130 +
   1.131 +    assert.equal(stack.pop().fileName, uri + "main.js",
   1.132 +                 "loader stack is omitted");
   1.133 +
   1.134 +    assert.equal(stack.pop().fileName, module.uri,
   1.135 +                 "previous in the stack is test module");
   1.136 +  } finally {
   1.137 +    unload(loader);
   1.138 +  }
   1.139 +}
   1.140 +
   1.141 +exports["test invalid module not cached and throws everytime"] = function(assert) {
   1.142 +  let uri = root + "/fixtures/loader/missing-twice/";
   1.143 +  let loader = Loader({ paths: { "": uri } });
   1.144 +
   1.145 +  let { firstError, secondError, invalidJSON1, invalidJSON2 } = main(loader, "main");
   1.146 +  assert.equal(firstError.message, "Module `not-found` is not found at " +
   1.147 +    uri + "not-found.js", "throws on first invalid require");
   1.148 +  assert.equal(firstError.lineNumber, 8, "first error is on line 7");
   1.149 +  assert.equal(secondError.message, "Module `not-found` is not found at " +
   1.150 +    uri + "not-found.js", "throws on second invalid require");
   1.151 +  assert.equal(secondError.lineNumber, 14, "second error is on line 14");
   1.152 +
   1.153 +  assert.equal(invalidJSON1.message,
   1.154 +    "JSON.parse: unexpected character at line 1 column 1 of the JSON data",
   1.155 +    "throws on invalid JSON");
   1.156 +  assert.equal(invalidJSON2.message,
   1.157 +    "JSON.parse: unexpected character at line 1 column 1 of the JSON data",
   1.158 +    "throws on invalid JSON second time");
   1.159 +};
   1.160 +
   1.161 +exports['test exceptions in modules'] = function(assert) {
   1.162 +  let uri = root + '/fixtures/loader/exceptions/'
   1.163 +
   1.164 +  let loader = Loader({ paths: { '': uri } });
   1.165 +
   1.166 +  try {
   1.167 +    let program = main(loader, 'main')
   1.168 +  } catch (error) {
   1.169 +    assert.equal(error.message, "Boom!", "thrown errors propagate");
   1.170 +
   1.171 +    assert.equal(error.fileName.split("/").pop(), "boomer.js",
   1.172 +                 "Error comes from the module that threw it");
   1.173 +
   1.174 +    assert.equal(error.lineNumber, 8, "error is on line 8");
   1.175 +
   1.176 +    let stack = parseStack(error.stack);
   1.177 +
   1.178 +    let frame = stack.pop()
   1.179 +    assert.equal(frame.fileName, uri + "boomer.js",
   1.180 +                 "module that threw is first in the stack");
   1.181 +    assert.equal(frame.name, "exports.boom",
   1.182 +                 "name is in the stack");
   1.183 +
   1.184 +    frame = stack.pop()
   1.185 +    assert.equal(frame.fileName, uri + "main.js",
   1.186 +                 "module that called it is next in the stack");
   1.187 +    assert.equal(frame.lineNumber, 9, "caller line is in the stack");
   1.188 +
   1.189 +
   1.190 +    assert.equal(stack.pop().fileName, module.uri,
   1.191 +                 "this test module is next in the stack");
   1.192 +  } finally {
   1.193 +    unload(loader);
   1.194 +  }
   1.195 +}
   1.196 +
   1.197 +exports['test early errors in module'] = function(assert) {
   1.198 +  let uri = root + '/fixtures/loader/errors/';
   1.199 +  let loader = Loader({ paths: { '': uri } });
   1.200 +
   1.201 +  try {
   1.202 +    let program = main(loader, 'main')
   1.203 +  } catch (error) {
   1.204 +    assert.equal(String(error),
   1.205 +                 "Error: opening input stream (invalid filename?)",
   1.206 +                 "thrown errors propagate");
   1.207 +
   1.208 +    assert.equal(error.fileName.split("/").pop(), "boomer.js",
   1.209 +                 "Error comes from the module that threw it");
   1.210 +
   1.211 +    assert.equal(error.lineNumber, 7, "error is on line 7");
   1.212 +
   1.213 +    let stack = parseStack(error.stack);
   1.214 +
   1.215 +    let frame = stack.pop()
   1.216 +    assert.equal(frame.fileName, uri + "boomer.js",
   1.217 +                 "module that threw is first in the stack");
   1.218 +
   1.219 +    frame = stack.pop()
   1.220 +    assert.equal(frame.fileName, uri + "main.js",
   1.221 +                 "module that called it is next in the stack");
   1.222 +    assert.equal(frame.lineNumber, 7, "caller line is in the stack");
   1.223 +
   1.224 +
   1.225 +    assert.equal(stack.pop().fileName, module.uri,
   1.226 +                 "this test module is next in the stack");
   1.227 +  } finally {
   1.228 +    unload(loader);
   1.229 +  }
   1.230 +};
   1.231 +
   1.232 +exports['test require json'] = function (assert) {
   1.233 +  let data = require('./fixtures/loader/json/manifest.json');
   1.234 +  assert.equal(data.name, 'Jetpack Loader Test', 'loads json with strings');
   1.235 +  assert.equal(data.version, '1.0.1', 'loads json with strings');
   1.236 +  assert.equal(data.dependencies.async, '*', 'loads json with objects');
   1.237 +  assert.equal(data.dependencies.underscore, '*', 'loads json with objects');
   1.238 +  assert.equal(data.contributors.length, 4, 'loads json with arrays');
   1.239 +  assert.ok(Array.isArray(data.contributors), 'loads json with arrays');
   1.240 +  data.version = '2.0.0';
   1.241 +  let newdata = require('./fixtures/loader/json/manifest.json');
   1.242 +  assert.equal(newdata.version, '2.0.0',
   1.243 +    'JSON objects returned should be cached and the same instance');
   1.244 +
   1.245 +  try {
   1.246 +    require('./fixtures/loader/json/invalid.json');
   1.247 +    assert.fail('Error not thrown when loading invalid json');
   1.248 +  } catch (err) {
   1.249 +    assert.ok(err, 'error thrown when loading invalid json');
   1.250 +    assert.ok(/JSON\.parse/.test(err.message),
   1.251 +      'should thrown an error from JSON.parse, not attempt to load .json.js');
   1.252 +  }
   1.253 +
   1.254 +  // Try again to ensure an empty module isn't loaded from cache
   1.255 +  try {
   1.256 +    require('./fixtures/loader/json/invalid.json');
   1.257 +    assert.fail('Error not thrown when loading invalid json a second time');
   1.258 +  } catch (err) {
   1.259 +    assert.ok(err,
   1.260 +      'error thrown when loading invalid json a second time');
   1.261 +    assert.ok(/JSON\.parse/.test(err.message),
   1.262 +      'should thrown an error from JSON.parse a second time, not attempt to load .json.js');
   1.263 +  }
   1.264 +};
   1.265 +
   1.266 +exports['test setting metadata for newly created sandboxes'] = function(assert) {
   1.267 +  let addonID = 'random-addon-id';
   1.268 +  let uri = root + '/fixtures/loader/cycles/';
   1.269 +  let loader = Loader({ paths: { '': uri }, id: addonID });
   1.270 +
   1.271 +  let dbg = new Debugger();
   1.272 +  dbg.onNewGlobalObject = function(global) {
   1.273 +    dbg.onNewGlobalObject = undefined;
   1.274 +
   1.275 +    let metadata = Cu.getSandboxMetadata(global.unsafeDereference());
   1.276 +    assert.ok(metadata, 'this global has attached metadata');
   1.277 +    assert.equal(metadata.URI, uri + 'main.js', 'URI is set properly');
   1.278 +    assert.equal(metadata.addonID, addonID, 'addon ID is set');
   1.279 +  }
   1.280 +
   1.281 +  let program = main(loader, 'main');
   1.282 +};
   1.283 +
   1.284 +exports['test require .json, .json.js'] = function (assert) {
   1.285 +  let testjson = require('./fixtures/loader/json/test.json');
   1.286 +  assert.equal(testjson.filename, 'test.json',
   1.287 +    'require("./x.json") should load x.json, not x.json.js');
   1.288 +
   1.289 +  let nodotjson = require('./fixtures/loader/json/nodotjson.json');
   1.290 +  assert.equal(nodotjson.filename, 'nodotjson.json.js',
   1.291 +    'require("./x.json") should load x.json.js when x.json does not exist');
   1.292 +  nodotjson.data.prop = 'hydralisk';
   1.293 +
   1.294 +  // require('nodotjson.json') and require('nodotjson.json.js')
   1.295 +  // should resolve to the same file
   1.296 +  let nodotjsonjs = require('./fixtures/loader/json/nodotjson.json.js');
   1.297 +  assert.equal(nodotjsonjs.data.prop, 'hydralisk',
   1.298 +    'js modules are cached whether access via .json.js or .json');
   1.299 +};
   1.300 +
   1.301 +exports['test invisibleToDebugger: false'] = function (assert) {
   1.302 +  let uri = root + '/fixtures/loader/cycles/';
   1.303 +  let loader = Loader({ paths: { '': uri } });
   1.304 +  main(loader, 'main');
   1.305 +
   1.306 +  let dbg = new Debugger();
   1.307 +  let sandbox = loader.sandboxes[uri + 'main.js'];
   1.308 +
   1.309 +  try {
   1.310 +    dbg.addDebuggee(sandbox);
   1.311 +    assert.ok(true, 'debugger added visible value');
   1.312 +  } catch(e) {
   1.313 +    assert.fail('debugger could not add visible value');
   1.314 +  }
   1.315 +};
   1.316 +
   1.317 +exports['test invisibleToDebugger: true'] = function (assert) {
   1.318 +  let uri = root + '/fixtures/loader/cycles/';
   1.319 +  let loader = Loader({ paths: { '': uri }, invisibleToDebugger: true });
   1.320 +  main(loader, 'main');
   1.321 +
   1.322 +  let dbg = new Debugger();
   1.323 +  let sandbox = loader.sandboxes[uri + 'main.js'];
   1.324 +
   1.325 +  try {
   1.326 +    dbg.addDebuggee(sandbox);
   1.327 +    assert.fail('debugger added invisible value');
   1.328 +  } catch(e) {
   1.329 +    assert.ok(true, 'debugger did not add invisible value');
   1.330 +  }
   1.331 +};
   1.332 +
   1.333 +exports['test console global by default'] = function (assert) {
   1.334 +  let uri = root + '/fixtures/loader/globals/';
   1.335 +  let loader = Loader({ paths: { '': uri }});
   1.336 +  let program = main(loader, 'main');
   1.337 + 
   1.338 +  assert.ok(typeof program.console === 'object', 'global `console` exists');
   1.339 +  assert.ok(typeof program.console.log === 'function', 'global `console.log` exists');
   1.340 +
   1.341 +  let loader2 = Loader({ paths: { '': uri }, globals: { console: fakeConsole }});
   1.342 +  let program2 = main(loader2, 'main');
   1.343 +
   1.344 +  assert.equal(program2.console, fakeConsole,
   1.345 +    'global console can be overridden with Loader options');
   1.346 +  function fakeConsole () {};
   1.347 +};
   1.348 +
   1.349 +require('test').run(exports);

mercurial