1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/modules/tests/xpcshell/test_task.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,387 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +/** 1.8 + * This file tests the Task.jsm module. 1.9 + */ 1.10 + 1.11 +//////////////////////////////////////////////////////////////////////////////// 1.12 +/// Globals 1.13 + 1.14 +const Cc = Components.classes; 1.15 +const Ci = Components.interfaces; 1.16 +const Cu = Components.utils; 1.17 +const Cr = Components.results; 1.18 + 1.19 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.20 + 1.21 +XPCOMUtils.defineLazyModuleGetter(this, "Promise", 1.22 + "resource://gre/modules/Promise.jsm"); 1.23 +XPCOMUtils.defineLazyModuleGetter(this, "Services", 1.24 + "resource://gre/modules/Services.jsm"); 1.25 +XPCOMUtils.defineLazyModuleGetter(this, "Task", 1.26 + "resource://gre/modules/Task.jsm"); 1.27 + 1.28 +/** 1.29 + * Returns a promise that will be resolved with the given value, when an event 1.30 + * posted on the event loop of the main thread is processed. 1.31 + */ 1.32 +function promiseResolvedLater(aValue) { 1.33 + let deferred = Promise.defer(); 1.34 + Services.tm.mainThread.dispatch(function () deferred.resolve(aValue), 1.35 + Ci.nsIThread.DISPATCH_NORMAL); 1.36 + return deferred.promise; 1.37 +} 1.38 + 1.39 +//////////////////////////////////////////////////////////////////////////////// 1.40 +/// Tests 1.41 + 1.42 +function run_test() 1.43 +{ 1.44 + run_next_test(); 1.45 +} 1.46 + 1.47 +add_test(function test_normal() 1.48 +{ 1.49 + Task.spawn(function () { 1.50 + let result = yield Promise.resolve("Value"); 1.51 + for (let i = 0; i < 3; i++) { 1.52 + result += yield promiseResolvedLater("!"); 1.53 + } 1.54 + throw new Task.Result("Task result: " + result); 1.55 + }).then(function (result) { 1.56 + do_check_eq("Task result: Value!!!", result); 1.57 + run_next_test(); 1.58 + }, function (ex) { 1.59 + do_throw("Unexpected error: " + ex); 1.60 + }); 1.61 +}); 1.62 + 1.63 +add_test(function test_exceptions() 1.64 +{ 1.65 + Task.spawn(function () { 1.66 + try { 1.67 + yield Promise.reject("Rejection result by promise."); 1.68 + do_throw("Exception expected because the promise was rejected."); 1.69 + } catch (ex) { 1.70 + // We catch this exception now, we will throw a different one later. 1.71 + do_check_eq("Rejection result by promise.", ex); 1.72 + } 1.73 + throw new Error("Exception uncaught by task."); 1.74 + }).then(function (result) { 1.75 + do_throw("Unexpected success!"); 1.76 + }, function (ex) { 1.77 + do_check_eq("Exception uncaught by task.", ex.message); 1.78 + run_next_test(); 1.79 + }); 1.80 +}); 1.81 + 1.82 +add_test(function test_recursion() 1.83 +{ 1.84 + function task_fibonacci(n) { 1.85 + throw new Task.Result(n < 2 ? n : (yield task_fibonacci(n - 1)) + 1.86 + (yield task_fibonacci(n - 2))); 1.87 + }; 1.88 + 1.89 + Task.spawn(task_fibonacci(6)).then(function (result) { 1.90 + do_check_eq(8, result); 1.91 + run_next_test(); 1.92 + }, function (ex) { 1.93 + do_throw("Unexpected error: " + ex); 1.94 + }); 1.95 +}); 1.96 + 1.97 +add_test(function test_spawn_primitive() 1.98 +{ 1.99 + function fibonacci(n) { 1.100 + return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); 1.101 + }; 1.102 + 1.103 + // Polymorphism between task and non-task functions (see "test_recursion"). 1.104 + Task.spawn(fibonacci(6)).then(function (result) { 1.105 + do_check_eq(8, result); 1.106 + run_next_test(); 1.107 + }, function (ex) { 1.108 + do_throw("Unexpected error: " + ex); 1.109 + }); 1.110 +}); 1.111 + 1.112 +add_test(function test_spawn_function() 1.113 +{ 1.114 + Task.spawn(function () { 1.115 + return "This is not a generator."; 1.116 + }).then(function (result) { 1.117 + do_check_eq("This is not a generator.", result); 1.118 + run_next_test(); 1.119 + }, function (ex) { 1.120 + do_throw("Unexpected error: " + ex); 1.121 + }); 1.122 +}); 1.123 + 1.124 +add_test(function test_spawn_function_this() 1.125 +{ 1.126 + Task.spawn(function () { 1.127 + return this; 1.128 + }).then(function (result) { 1.129 + // Since the task function wasn't defined in strict mode, its "this" object 1.130 + // should be the same as the "this" object in this function, i.e. the global 1.131 + // object. 1.132 + do_check_eq(result, this); 1.133 + run_next_test(); 1.134 + }, function (ex) { 1.135 + do_throw("Unexpected error: " + ex); 1.136 + }); 1.137 +}); 1.138 + 1.139 +add_test(function test_spawn_function_this_strict() 1.140 +{ 1.141 + "use strict"; 1.142 + Task.spawn(function () { 1.143 + return this; 1.144 + }).then(function (result) { 1.145 + // Since the task function was defined in strict mode, its "this" object 1.146 + // should be undefined. 1.147 + do_check_eq(typeof(result), "undefined"); 1.148 + run_next_test(); 1.149 + }, function (ex) { 1.150 + do_throw("Unexpected error: " + ex); 1.151 + }); 1.152 +}); 1.153 + 1.154 +add_test(function test_spawn_function_returning_promise() 1.155 +{ 1.156 + Task.spawn(function () { 1.157 + return promiseResolvedLater("Resolution value."); 1.158 + }).then(function (result) { 1.159 + do_check_eq("Resolution value.", result); 1.160 + run_next_test(); 1.161 + }, function (ex) { 1.162 + do_throw("Unexpected error: " + ex); 1.163 + }); 1.164 +}); 1.165 + 1.166 +add_test(function test_spawn_function_exceptions() 1.167 +{ 1.168 + Task.spawn(function () { 1.169 + throw new Error("Exception uncaught by task."); 1.170 + }).then(function (result) { 1.171 + do_throw("Unexpected success!"); 1.172 + }, function (ex) { 1.173 + do_check_eq("Exception uncaught by task.", ex.message); 1.174 + run_next_test(); 1.175 + }); 1.176 +}); 1.177 + 1.178 +add_test(function test_spawn_function_taskresult() 1.179 +{ 1.180 + Task.spawn(function () { 1.181 + throw new Task.Result("Task result"); 1.182 + }).then(function (result) { 1.183 + do_check_eq("Task result", result); 1.184 + run_next_test(); 1.185 + }, function (ex) { 1.186 + do_throw("Unexpected error: " + ex); 1.187 + }); 1.188 +}); 1.189 + 1.190 +add_test(function test_yielded_undefined() 1.191 +{ 1.192 + Task.spawn(function () { 1.193 + yield; 1.194 + throw new Task.Result("We continued correctly."); 1.195 + }).then(function (result) { 1.196 + do_check_eq("We continued correctly.", result); 1.197 + run_next_test(); 1.198 + }, function (ex) { 1.199 + do_throw("Unexpected error: " + ex); 1.200 + }); 1.201 +}); 1.202 + 1.203 +add_test(function test_yielded_primitive() 1.204 +{ 1.205 + Task.spawn(function () { 1.206 + throw new Task.Result("Primitive " + (yield "value.")); 1.207 + }).then(function (result) { 1.208 + do_check_eq("Primitive value.", result); 1.209 + run_next_test(); 1.210 + }, function (ex) { 1.211 + do_throw("Unexpected error: " + ex); 1.212 + }); 1.213 +}); 1.214 + 1.215 +add_test(function test_star_normal() 1.216 +{ 1.217 + Task.spawn(function* () { 1.218 + let result = yield Promise.resolve("Value"); 1.219 + for (let i = 0; i < 3; i++) { 1.220 + result += yield promiseResolvedLater("!"); 1.221 + } 1.222 + return "Task result: " + result; 1.223 + }).then(function (result) { 1.224 + do_check_eq("Task result: Value!!!", result); 1.225 + run_next_test(); 1.226 + }, function (ex) { 1.227 + do_throw("Unexpected error: " + ex); 1.228 + }); 1.229 +}); 1.230 + 1.231 +add_test(function test_star_exceptions() 1.232 +{ 1.233 + Task.spawn(function* () { 1.234 + try { 1.235 + yield Promise.reject("Rejection result by promise."); 1.236 + do_throw("Exception expected because the promise was rejected."); 1.237 + } catch (ex) { 1.238 + // We catch this exception now, we will throw a different one later. 1.239 + do_check_eq("Rejection result by promise.", ex); 1.240 + } 1.241 + throw new Error("Exception uncaught by task."); 1.242 + }).then(function (result) { 1.243 + do_throw("Unexpected success!"); 1.244 + }, function (ex) { 1.245 + do_check_eq("Exception uncaught by task.", ex.message); 1.246 + run_next_test(); 1.247 + }); 1.248 +}); 1.249 + 1.250 +add_test(function test_star_recursion() 1.251 +{ 1.252 + function* task_fibonacci(n) { 1.253 + return n < 2 ? n : (yield task_fibonacci(n - 1)) + 1.254 + (yield task_fibonacci(n - 2)); 1.255 + }; 1.256 + 1.257 + Task.spawn(task_fibonacci(6)).then(function (result) { 1.258 + do_check_eq(8, result); 1.259 + run_next_test(); 1.260 + }, function (ex) { 1.261 + do_throw("Unexpected error: " + ex); 1.262 + }); 1.263 +}); 1.264 + 1.265 +add_test(function test_mixed_legacy_and_star() 1.266 +{ 1.267 + Task.spawn(function* () { 1.268 + return yield (function() { 1.269 + throw new Task.Result(yield 5); 1.270 + })(); 1.271 + }).then(function (result) { 1.272 + do_check_eq(5, result); 1.273 + run_next_test(); 1.274 + }, function (ex) { 1.275 + do_throw("Unexpected error: " + ex); 1.276 + }); 1.277 +}); 1.278 + 1.279 +add_test(function test_async_function_from_generator() 1.280 +{ 1.281 + Task.spawn(function* () { 1.282 + let object = { 1.283 + asyncFunction: Task.async(function* (param) { 1.284 + do_check_eq(this, object); 1.285 + return param; 1.286 + }) 1.287 + }; 1.288 + 1.289 + // Ensure the async function returns a promise that resolves as expected. 1.290 + do_check_eq((yield object.asyncFunction(1)), 1); 1.291 + 1.292 + // Ensure a second call to the async function also returns such a promise. 1.293 + do_check_eq((yield object.asyncFunction(3)), 3); 1.294 + }).then(function () { 1.295 + run_next_test(); 1.296 + }, function (ex) { 1.297 + do_throw("Unexpected error: " + ex); 1.298 + }); 1.299 +}); 1.300 + 1.301 +add_test(function test_async_function_from_function() 1.302 +{ 1.303 + Task.spawn(function* () { 1.304 + return Task.spawn(function* () { 1.305 + let object = { 1.306 + asyncFunction: Task.async(function (param) { 1.307 + do_check_eq(this, object); 1.308 + return param; 1.309 + }) 1.310 + }; 1.311 + 1.312 + // Ensure the async function returns a promise that resolves as expected. 1.313 + do_check_eq((yield object.asyncFunction(5)), 5); 1.314 + 1.315 + // Ensure a second call to the async function also returns such a promise. 1.316 + do_check_eq((yield object.asyncFunction(7)), 7); 1.317 + }); 1.318 + }).then(function () { 1.319 + run_next_test(); 1.320 + }, function (ex) { 1.321 + do_throw("Unexpected error: " + ex); 1.322 + }); 1.323 +}); 1.324 + 1.325 +add_test(function test_async_function_that_throws_rejects_promise() 1.326 +{ 1.327 + Task.spawn(function* () { 1.328 + let object = { 1.329 + asyncFunction: Task.async(function* () { 1.330 + throw "Rejected!"; 1.331 + }) 1.332 + }; 1.333 + 1.334 + yield object.asyncFunction(); 1.335 + }).then(function () { 1.336 + do_throw("unexpected success calling async function that throws error"); 1.337 + }, function (ex) { 1.338 + do_check_eq(ex, "Rejected!"); 1.339 + run_next_test(); 1.340 + }); 1.341 +}); 1.342 + 1.343 +add_test(function test_async_return_function() 1.344 +{ 1.345 + Task.spawn(function* () { 1.346 + // Ensure an async function that returns a function resolves to the function 1.347 + // itself instead of calling the function and resolving to its return value. 1.348 + return Task.spawn(function* () { 1.349 + let returnValue = function () { 1.350 + return "These aren't the droids you're looking for."; 1.351 + }; 1.352 + 1.353 + let asyncFunction = Task.async(function () { 1.354 + return returnValue; 1.355 + }); 1.356 + 1.357 + do_check_eq((yield asyncFunction()), returnValue); 1.358 + }); 1.359 + }).then(function () { 1.360 + run_next_test(); 1.361 + }, function (ex) { 1.362 + do_throw("Unexpected error: " + ex); 1.363 + }); 1.364 +}); 1.365 + 1.366 +add_test(function test_async_throw_argument_not_function() 1.367 +{ 1.368 + Task.spawn(function* () { 1.369 + // Ensure Task.async throws if its aTask argument is not a function. 1.370 + Assert.throws(() => Task.async("not a function"), 1.371 + /aTask argument must be a function/); 1.372 + }).then(function () { 1.373 + run_next_test(); 1.374 + }, function (ex) { 1.375 + do_throw("Unexpected error: " + ex); 1.376 + }); 1.377 +}); 1.378 + 1.379 +add_test(function test_async_throw_on_function_in_place_of_promise() 1.380 +{ 1.381 + Task.spawn(function* () { 1.382 + // Ensure Task.spawn throws if passed an async function. 1.383 + Assert.throws(() => Task.spawn(Task.async(function* () {})), 1.384 + /Cannot use an async function in place of a promise/); 1.385 + }).then(function () { 1.386 + run_next_test(); 1.387 + }, function (ex) { 1.388 + do_throw("Unexpected error: " + ex); 1.389 + }); 1.390 +});