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

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 'use strict';
michael@0 6
michael@0 7 const { Cc, Cu, Ci } = require('chrome');
michael@0 8 const { setTimeout } = require('sdk/timers');
michael@0 9 const { prefixURI, name } = require('@loader/options');
michael@0 10 const addonPromiseURI = prefixURI + name + '/lib/sdk/core/promise.js';
michael@0 11 const builtPromiseURI = 'resource://gre/modules/commonjs/sdk/core/promise.js';
michael@0 12 let { Promise, defer, resolve, reject, all, promised } = require('sdk/core/promise');
michael@0 13
michael@0 14 exports['test all observers are notified'] = function(assert, done) {
michael@0 15 let expected = 'Taram pam param!';
michael@0 16 let deferred = defer();
michael@0 17 let pending = 10, i = 0;
michael@0 18
michael@0 19 function resolved(value) {
michael@0 20 assert.equal(value, expected, 'value resolved as expected: #' + pending);
michael@0 21 if (!--pending) done();
michael@0 22 }
michael@0 23
michael@0 24 while (i++ < pending) deferred.promise.then(resolved);
michael@0 25
michael@0 26 deferred.resolve(expected);
michael@0 27 };
michael@0 28
michael@0 29 exports['test exceptions dont stop notifications'] = function(assert, done) {
michael@0 30 let threw = false, boom = Error('Boom!');
michael@0 31 let deferred = defer();
michael@0 32
michael@0 33 let promise2 = deferred.promise.then(function() {
michael@0 34 threw = true;
michael@0 35 throw boom;
michael@0 36 });
michael@0 37
michael@0 38 deferred.promise.then(function() {
michael@0 39 assert.ok(threw, 'observer is called even though previos one threw');
michael@0 40 promise2.then(function() {
michael@0 41 assert.fail('should not resolve');
michael@0 42 }, function(reason) {
michael@0 43 assert.equal(reason, boom, 'rejects to thrown error');
michael@0 44 done();
michael@0 45 });
michael@0 46 });
michael@0 47
michael@0 48 deferred.resolve('go!');
michael@0 49 };
michael@0 50
michael@0 51 exports['test subsequent resolves are ignored'] = function(assert, done) {
michael@0 52 let deferred = defer();
michael@0 53 deferred.resolve(1);
michael@0 54 deferred.resolve(2);
michael@0 55 deferred.reject(3);
michael@0 56
michael@0 57 deferred.promise.then(function(actual) {
michael@0 58 assert.equal(actual, 1, 'resolves to first value');
michael@0 59 }, function() {
michael@0 60 assert.fail('must not reject');
michael@0 61 });
michael@0 62 deferred.promise.then(function(actual) {
michael@0 63 assert.equal(actual, 1, 'subsequent resolutions are ignored');
michael@0 64 done();
michael@0 65 }, function() {
michael@0 66 assert.fail('must not reject');
michael@0 67 });
michael@0 68 };
michael@0 69
michael@0 70 exports['test subsequent rejections are ignored'] = function(assert, done) {
michael@0 71 let deferred = defer();
michael@0 72 deferred.reject(1);
michael@0 73 deferred.resolve(2);
michael@0 74 deferred.reject(3);
michael@0 75
michael@0 76 deferred.promise.then(function(actual) {
michael@0 77 assert.fail('must not resolve');
michael@0 78 }, function(actual) {
michael@0 79 assert.equal(actual, 1, 'must reject to first');
michael@0 80 });
michael@0 81 deferred.promise.then(function(actual) {
michael@0 82 assert.fail('must not resolve');
michael@0 83 }, function(actual) {
michael@0 84 assert.equal(actual, 1, 'must reject to first');
michael@0 85 done();
michael@0 86 });
michael@0 87 };
michael@0 88
michael@0 89 exports['test error recovery'] = function(assert, done) {
michael@0 90 let boom = Error('Boom!');
michael@0 91 let deferred = defer();
michael@0 92
michael@0 93 deferred.promise.then(function() {
michael@0 94 assert.fail('rejected promise should not resolve');
michael@0 95 }, function(reason) {
michael@0 96 assert.equal(reason, boom, 'rejection reason delivered');
michael@0 97 return 'recovery';
michael@0 98 }).then(function(value) {
michael@0 99 assert.equal(value, 'recovery', 'error handled by a handler');
michael@0 100 done();
michael@0 101 });
michael@0 102
michael@0 103 deferred.reject(boom);
michael@0 104 };
michael@0 105
michael@0 106 exports['test error recovery with promise'] = function(assert, done) {
michael@0 107 let deferred = defer();
michael@0 108
michael@0 109 deferred.promise.then(function() {
michael@0 110 assert.fail('must reject');
michael@0 111 }, function(actual) {
michael@0 112 assert.equal(actual, 'reason', 'rejected');
michael@0 113 let deferred = defer();
michael@0 114 deferred.resolve('recovery');
michael@0 115 return deferred.promise;
michael@0 116 }).then(function(actual) {
michael@0 117 assert.equal(actual, 'recovery', 'recorvered via promise');
michael@0 118 let deferred = defer();
michael@0 119 deferred.reject('error');
michael@0 120 return deferred.promise;
michael@0 121 }).then(null, function(actual) {
michael@0 122 assert.equal(actual, 'error', 'rejected via promise');
michael@0 123 let deferred = defer();
michael@0 124 deferred.reject('end');
michael@0 125 return deferred.promise;
michael@0 126 }).then(null, function(actual) {
michael@0 127 assert.equal(actual, 'end', 'rejeced via promise');
michael@0 128 done();
michael@0 129 });
michael@0 130
michael@0 131 deferred.reject('reason');
michael@0 132 };
michael@0 133
michael@0 134 exports['test propagation'] = function(assert, done) {
michael@0 135 let d1 = defer(), d2 = defer(), d3 = defer();
michael@0 136
michael@0 137 d1.promise.then(function(actual) {
michael@0 138 assert.equal(actual, 'expected', 'resolves to expected value');
michael@0 139 done();
michael@0 140 });
michael@0 141
michael@0 142 d1.resolve(d2.promise);
michael@0 143 d2.resolve(d3.promise);
michael@0 144 d3.resolve('expected');
michael@0 145 };
michael@0 146
michael@0 147 exports['test chaining'] = function(assert, done) {
michael@0 148 let boom = Error('boom'), brax = Error('braxXXx');
michael@0 149 let deferred = defer();
michael@0 150
michael@0 151 deferred.promise.then().then().then(function(actual) {
michael@0 152 assert.equal(actual, 2, 'value propagates unchanged');
michael@0 153 return actual + 2;
michael@0 154 }).then(null, function(reason) {
michael@0 155 assert.fail('should not reject');
michael@0 156 }).then(function(actual) {
michael@0 157 assert.equal(actual, 4, 'value propagates through if not handled');
michael@0 158 throw boom;
michael@0 159 }).then(function(actual) {
michael@0 160 assert.fail('exception must reject promise');
michael@0 161 }).then().then(null, function(actual) {
michael@0 162 assert.equal(actual, boom, 'reason propagates unchanged');
michael@0 163 throw brax;
michael@0 164 }).then().then(null, function(actual) {
michael@0 165 assert.equal(actual, brax, 'reason changed becase of exception');
michael@0 166 return 'recovery';
michael@0 167 }).then(function(actual) {
michael@0 168 assert.equal(actual, 'recovery', 'recovered from error');
michael@0 169 done();
michael@0 170 });
michael@0 171
michael@0 172 deferred.resolve(2);
michael@0 173 };
michael@0 174
michael@0 175 exports['test reject'] = function(assert, done) {
michael@0 176 let expected = Error('boom');
michael@0 177
michael@0 178 reject(expected).then(function() {
michael@0 179 assert.fail('should reject');
michael@0 180 }, function(actual) {
michael@0 181 assert.equal(actual, expected, 'rejected with expected reason');
michael@0 182 }).then(done, assert.fail);
michael@0 183 };
michael@0 184
michael@0 185 exports['test resolve to rejected'] = function(assert, done) {
michael@0 186 let expected = Error('boom');
michael@0 187 let deferred = defer();
michael@0 188
michael@0 189 deferred.promise.then(function() {
michael@0 190 assert.fail('should reject');
michael@0 191 }, function(actual) {
michael@0 192 assert.equal(actual, expected, 'rejected with expected failure');
michael@0 193 }).then(done, assert.fail);
michael@0 194
michael@0 195 deferred.resolve(reject(expected));
michael@0 196 };
michael@0 197
michael@0 198 exports['test resolve'] = function(assert, done) {
michael@0 199 let expected = 'value';
michael@0 200 resolve(expected).then(function(actual) {
michael@0 201 assert.equal(actual, expected, 'resolved as expected');
michael@0 202 }).catch(assert.fail).then(done);
michael@0 203 };
michael@0 204
michael@0 205 exports['test promised with normal args'] = function(assert, done) {
michael@0 206 let sum = promised((x, y) => x + y );
michael@0 207
michael@0 208 sum(7, 8).then(function(actual) {
michael@0 209 assert.equal(actual, 7 + 8, 'resolves as expected');
michael@0 210 }).catch(assert.fail).then(done);
michael@0 211 };
michael@0 212
michael@0 213 exports['test promised with promise args'] = function(assert, done) {
michael@0 214 let sum = promised((x, y) => x + y );
michael@0 215 let deferred = defer();
michael@0 216
michael@0 217 sum(11, deferred.promise).then(function(actual) {
michael@0 218 assert.equal(actual, 11 + 24, 'resolved as expected');
michael@0 219 }).catch(assert.fail).then(done);
michael@0 220
michael@0 221 deferred.resolve(24);
michael@0 222 };
michael@0 223
michael@0 224 exports['test promised error handleing'] = function(assert, done) {
michael@0 225 let expected = Error('boom');
michael@0 226 let f = promised(function() {
michael@0 227 throw expected;
michael@0 228 });
michael@0 229
michael@0 230 f().then(function() {
michael@0 231 assert.fail('should reject');
michael@0 232 }, function(actual) {
michael@0 233 assert.equal(actual, expected, 'rejected as expected');
michael@0 234 }).catch(assert.fail).then(done);
michael@0 235 };
michael@0 236
michael@0 237 exports['test errors in promise resolution handlers are propagated'] = function(assert, done) {
michael@0 238 var expected = Error('Boom');
michael@0 239 var { promise, resolve } = defer();
michael@0 240
michael@0 241 promise.then(function() {
michael@0 242 throw expected;
michael@0 243 }).then(function() {
michael@0 244 return undefined;
michael@0 245 }).then(null, function(actual) {
michael@0 246 assert.equal(actual, expected, 'rejected as expected');
michael@0 247 }).then(done, assert.fail);
michael@0 248
michael@0 249 resolve({});
michael@0 250 };
michael@0 251
michael@0 252 exports['test return promise form promised'] = function(assert, done) {
michael@0 253 let f = promised(function() {
michael@0 254 return resolve(17);
michael@0 255 });
michael@0 256
michael@0 257 f().then(function(actual) {
michael@0 258 assert.equal(actual, 17, 'resolves to a promise resolution');
michael@0 259 }).catch(assert.fail).then(done);
michael@0 260 };
michael@0 261
michael@0 262 exports['test promised returning failure'] = function(assert, done) {
michael@0 263 let expected = Error('boom');
michael@0 264 let f = promised(function() {
michael@0 265 return reject(expected);
michael@0 266 });
michael@0 267
michael@0 268 f().then(function() {
michael@0 269 assert.fail('must reject');
michael@0 270 }, function(actual) {
michael@0 271 assert.equal(actual, expected, 'rejects with expected reason');
michael@0 272 }).catch(assert.fail).then(done);
michael@0 273 };
michael@0 274
michael@0 275 /*
michael@0 276 * Changed for compliance in Bug 881047, promises are now always async
michael@0 277 */
michael@0 278 exports['test promises are always async'] = function (assert, done) {
michael@0 279 let runs = 0;
michael@0 280 resolve(1)
michael@0 281 .then(val => ++runs)
michael@0 282 .catch(assert.fail).then(done);
michael@0 283 assert.equal(runs, 0, 'resolutions are called in following tick');
michael@0 284 };
michael@0 285
michael@0 286 /*
michael@0 287 * Changed for compliance in Bug 881047, promised's are now non greedy
michael@0 288 */
michael@0 289 exports['test promised are not greedy'] = function(assert, done) {
michael@0 290 let runs = 0;
michael@0 291 promised(() => ++runs)()
michael@0 292 .catch(assert.fail).then(done);
michael@0 293 assert.equal(runs, 0, 'promised does not run task right away');
michael@0 294 };
michael@0 295
michael@0 296 exports['test arrays should not flatten'] = function(assert, done) {
michael@0 297 let a = defer();
michael@0 298 let b = defer();
michael@0 299
michael@0 300 let combine = promised(function(str, arr) {
michael@0 301 assert.equal(str, 'Hello', 'Array was not flattened');
michael@0 302 assert.deepEqual(arr, [ 'my', 'friend' ]);
michael@0 303 });
michael@0 304
michael@0 305 combine(a.promise, b.promise).catch(assert.fail).then(done);
michael@0 306
michael@0 307
michael@0 308 a.resolve('Hello');
michael@0 309 b.resolve([ 'my', 'friend' ]);
michael@0 310 };
michael@0 311
michael@0 312 exports['test `all` for all promises'] = function (assert, done) {
michael@0 313 all([
michael@0 314 resolve(5), resolve(7), resolve(10)
michael@0 315 ]).then(function (val) {
michael@0 316 assert.equal(
michael@0 317 val[0] === 5 &&
michael@0 318 val[1] === 7 &&
michael@0 319 val[2] === 10
michael@0 320 , true, 'return value contains resolved promises values');
michael@0 321 done();
michael@0 322 }, function () {
michael@0 323 assert.fail('should not call reject function');
michael@0 324 });
michael@0 325 };
michael@0 326
michael@0 327 exports['test `all` aborts upon first reject'] = function (assert, done) {
michael@0 328 all([
michael@0 329 resolve(5), reject('error'), delayedResolve()
michael@0 330 ]).then(function (val) {
michael@0 331 assert.fail('Successful resolve function should not be called');
michael@0 332 }, function (reason) {
michael@0 333 assert.equal(reason, 'error', 'should reject the `all` promise');
michael@0 334 done();
michael@0 335 });
michael@0 336
michael@0 337 function delayedResolve () {
michael@0 338 let deferred = defer();
michael@0 339 setTimeout(deferred.resolve, 50);
michael@0 340 return deferred.promise;
michael@0 341 }
michael@0 342 };
michael@0 343
michael@0 344 exports['test `all` with array containing non-promise'] = function (assert, done) {
michael@0 345 all([
michael@0 346 resolve(5), resolve(10), 925
michael@0 347 ]).then(function (val) {
michael@0 348 assert.equal(val[2], 925, 'non-promises should pass-through value');
michael@0 349 done();
michael@0 350 }, function () {
michael@0 351 assert.fail('should not be rejected');
michael@0 352 });
michael@0 353 };
michael@0 354
michael@0 355 exports['test `all` should resolve with an empty array'] = function (assert, done) {
michael@0 356 all([]).then(function (val) {
michael@0 357 assert.equal(Array.isArray(val), true, 'should return array in resolved');
michael@0 358 assert.equal(val.length, 0, 'array should be empty in resolved');
michael@0 359 done();
michael@0 360 }, function () {
michael@0 361 assert.fail('should not be rejected');
michael@0 362 });
michael@0 363 };
michael@0 364
michael@0 365 exports['test `all` with multiple rejected'] = function (assert, done) {
michael@0 366 all([
michael@0 367 reject('error1'), reject('error2'), reject('error3')
michael@0 368 ]).then(function (value) {
michael@0 369 assert.fail('should not be successful');
michael@0 370 }, function (reason) {
michael@0 371 assert.equal(reason, 'error1', 'should reject on first promise reject');
michael@0 372 done();
michael@0 373 });
michael@0 374 };
michael@0 375
michael@0 376 exports['test Promise constructor resolve'] = function (assert, done) {
michael@0 377 var isAsync = true;
michael@0 378 new Promise(function (resolve, reject) {
michael@0 379 resolve(5);
michael@0 380 }).then(x => {
michael@0 381 isAsync = false;
michael@0 382 assert.equal(x, 5, 'Promise constructor resolves correctly');
michael@0 383 }).catch(assert.fail).then(done);
michael@0 384 assert.ok(isAsync, 'Promise constructor runs async');
michael@0 385 };
michael@0 386
michael@0 387 exports['test Promise constructor reject'] = function (assert, done) {
michael@0 388 new Promise(function (resolve, reject) {
michael@0 389 reject(new Error('deferred4life'));
michael@0 390 }).then(assert.fail, (err) => {
michael@0 391 assert.equal(err.message, 'deferred4life', 'Promise constructor rejects correctly');
michael@0 392 }).catch(assert.fail).then(done);
michael@0 393 };
michael@0 394
michael@0 395 exports['test JSM Load and API'] = function (assert, done) {
michael@0 396 // Use addon URL when loading from cfx/local:
michael@0 397 // resource://90111c90-c31e-4dc7-ac35-b65947434435-at-jetpack/addon-sdk/lib/sdk/core/promise.js
michael@0 398 // Use built URL when testing on try, etc.
michael@0 399 // resource://gre/modules/commonjs/sdk/core/promise.js
michael@0 400 try {
michael@0 401 var { Promise } = Cu.import(addonPromiseURI, {});
michael@0 402 } catch (e) {
michael@0 403 var { Promise } = Cu.import(builtPromiseURI, {});
michael@0 404 }
michael@0 405 testEnvironment(Promise, assert, done, 'JSM');
michael@0 406 };
michael@0 407
michael@0 408 exports['test mozIJSSubScriptLoader exporting'] = function (assert, done) {
michael@0 409 let { Services } = Cu.import('resource://gre/modules/Services.jsm', {});
michael@0 410 let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
michael@0 411 let Promise = new Cu.Sandbox(systemPrincipal);
michael@0 412 let loader = Cc['@mozilla.org/moz/jssubscript-loader;1']
michael@0 413 .getService(Ci.mozIJSSubScriptLoader);
michael@0 414
michael@0 415 // Use addon URL when loading from cfx/local:
michael@0 416 // resource://90111c90-c31e-4dc7-ac35-b65947434435-at-jetpack/addon-sdk/lib/sdk/core/promise.js
michael@0 417 // Use built URL when testing on try, etc.
michael@0 418 // resource://gre/modules/commonjs/sdk/core/promise.js
michael@0 419 try {
michael@0 420 loader.loadSubScript(addonPromiseURI, Promise);
michael@0 421 } catch (e) {
michael@0 422 loader.loadSubScript(builtPromiseURI, Promise);
michael@0 423 }
michael@0 424
michael@0 425 testEnvironment(Promise, assert, done, 'mozIJSSubScript');
michael@0 426 };
michael@0 427
michael@0 428 function testEnvironment ({all, resolve, defer, reject, promised}, assert, done, type) {
michael@0 429 all([resolve(5), resolve(10), 925]).then(val => {
michael@0 430 assert.equal(val[0], 5, 'promise#all works ' + type);
michael@0 431 assert.equal(val[1], 10, 'promise#all works ' + type);
michael@0 432 assert.equal(val[2], 925, 'promise#all works ' + type);
michael@0 433 return resolve(1000);
michael@0 434 }).then(value => {
michael@0 435 assert.equal(value, 1000, 'promise#resolve works ' + type);
michael@0 436 return reject('testing reject');
michael@0 437 }).then(null, reason => {
michael@0 438 assert.equal(reason, 'testing reject', 'promise#reject works ' + type);
michael@0 439 let deferred = defer();
michael@0 440 setTimeout(() => deferred.resolve('\\m/'), 10);
michael@0 441 return deferred.promise;
michael@0 442 }).then(value => {
michael@0 443 assert.equal(value, '\\m/', 'promise#defer works ' + type);
michael@0 444 return promised(x => x * x)(5);
michael@0 445 }).then(value => {
michael@0 446 assert.equal(value, 25, 'promise#promised works ' + type);
michael@0 447 }).then(done, assert.fail);
michael@0 448 }
michael@0 449
michael@0 450 require("sdk/test").run(exports);

mercurial