michael@0: /* -*- Mode: js; js-indent-level: 2; -*- */ michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: // Test async-utils.js michael@0: michael@0: const {Task} = Cu.import("resource://gre/modules/Task.jsm", {}); michael@0: // |const| will not work because michael@0: // it will make the Promise object immutable before assigning. michael@0: // Using Object.defineProperty() instead. michael@0: Object.defineProperty(this, "Promise", { michael@0: value: Cu.import("resource://gre/modules/Promise.jsm", {}).Promise, michael@0: writable: false, configurable: false michael@0: }); michael@0: const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; michael@0: const {async, asyncOnce, promiseInvoke, promiseCall} = require("devtools/async-utils"); michael@0: michael@0: function run_test() { michael@0: do_test_pending(); michael@0: Task.spawn(function*() { michael@0: for (let helper of [async, asyncOnce]) { michael@0: yield test_async_args(helper); michael@0: yield test_async_return(helper); michael@0: yield test_async_throw(helper); michael@0: } michael@0: yield test_async_once(); michael@0: yield test_async_invoke(); michael@0: do_test_finished(); michael@0: }).then(null, error => { michael@0: do_throw(error); michael@0: }); michael@0: } michael@0: michael@0: // Test that arguments are correctly passed through to the async function. michael@0: function test_async_args(async) { michael@0: let obj = { michael@0: method: async(function*(a, b) { michael@0: do_check_eq(this, obj); michael@0: do_check_eq(a, "foo"); michael@0: do_check_eq(b, "bar"); michael@0: }) michael@0: }; michael@0: michael@0: return obj.method("foo", "bar"); michael@0: } michael@0: michael@0: // Test that the return value from the async function is resolution value of michael@0: // the promise. michael@0: function test_async_return(async) { michael@0: let obj = { michael@0: method: async(function*(a, b) { michael@0: return a + b; michael@0: }) michael@0: }; michael@0: michael@0: return obj.method("foo", "bar").then(ret => { michael@0: do_check_eq(ret, "foobar"); michael@0: }); michael@0: } michael@0: michael@0: // Test that the throwing from an async function rejects the promise. michael@0: function test_async_throw(async) { michael@0: let obj = { michael@0: method: async(function*() { michael@0: throw "boom"; michael@0: }) michael@0: }; michael@0: michael@0: return obj.method().then(null, error => { michael@0: do_check_eq(error, "boom"); michael@0: }); michael@0: } michael@0: michael@0: // Test that asyncOnce only runs the async function once per instance and michael@0: // returns the same promise for that instance. michael@0: function test_async_once() { michael@0: let counter = 0; michael@0: michael@0: function Foo() {} michael@0: Foo.prototype = { michael@0: ran: false, michael@0: method: asyncOnce(function*() { michael@0: yield Promise.resolve(); michael@0: if (this.ran) { michael@0: do_throw("asyncOnce function unexpectedly ran twice on the same object"); michael@0: } michael@0: this.ran = true; michael@0: return counter++; michael@0: }) michael@0: }; michael@0: michael@0: let foo1 = new Foo(); michael@0: let foo2 = new Foo(); michael@0: let p1 = foo1.method(); michael@0: let p2 = foo2.method(); michael@0: michael@0: do_check_neq(p1, p2); michael@0: michael@0: let p3 = foo1.method(); michael@0: do_check_eq(p1, p3); michael@0: do_check_false(foo1.ran); michael@0: michael@0: let p4 = foo2.method(); michael@0: do_check_eq(p2, p4); michael@0: do_check_false(foo2.ran); michael@0: michael@0: return p1.then(ret => { michael@0: do_check_true(foo1.ran); michael@0: do_check_eq(ret, 0); michael@0: return p2; michael@0: }).then(ret => { michael@0: do_check_true(foo2.ran); michael@0: do_check_eq(ret, 1); michael@0: }); michael@0: } michael@0: michael@0: // Test invoke and call. michael@0: function test_async_invoke() { michael@0: return Task.spawn(function*() { michael@0: function func(a, b, expectedThis, callback) { michael@0: "use strict"; michael@0: do_check_eq(a, "foo"); michael@0: do_check_eq(b, "bar"); michael@0: do_check_eq(this, expectedThis); michael@0: callback(a + b); michael@0: } michael@0: michael@0: // Test call. michael@0: let callResult = yield promiseCall(func, "foo", "bar", undefined); michael@0: do_check_eq(callResult, "foobar"); michael@0: michael@0: michael@0: // Test invoke. michael@0: let obj = { method: func }; michael@0: let invokeResult = yield promiseInvoke(obj, obj.method, "foo", "bar", obj); michael@0: do_check_eq(invokeResult, "foobar"); michael@0: michael@0: michael@0: // Test passing multiple values to the callback. michael@0: function multipleResults(callback) { michael@0: callback("foo", "bar"); michael@0: } michael@0: michael@0: let results = yield promiseCall(multipleResults); michael@0: do_check_eq(results.length, 2); michael@0: do_check_eq(results[0], "foo"); michael@0: do_check_eq(results[1], "bar"); michael@0: michael@0: michael@0: // Test throwing from the function. michael@0: function thrower() { michael@0: throw "boom"; michael@0: } michael@0: michael@0: yield promiseCall(thrower).then(null, error => { michael@0: do_check_eq(error, "boom"); michael@0: }); michael@0: }); michael@0: }