Bug 1473614 - Add type checks to PollPromise and TimedPromise. r=automatedtester

This patch introduces stricted type checks for the sync module's
PollPromise and TimedPromise.  This may seem excessive, but we have
had real and severe bugs in this area before.
This commit is contained in:
Andreas Tolfsen 2018-08-03 16:08:45 +01:00
Родитель 91412a8686
Коммит 475e6da1d9
2 изменённых файлов: 92 добавлений и 3 удалений

Просмотреть файл

@ -86,10 +86,25 @@ const {TYPE_ONE_SHOT, TYPE_REPEATING_SLACK} = Ci.nsITimer;
*
* @throws {*}
* If ``func`` throws, its error is propagated.
* @throws {TypeError}
* If `timeout` or `interval`` are not numbers.
* @throws {RangeError}
* If `timeout` or `interval` are not unsigned integers.
*/
function PollPromise(func, {timeout = 2000, interval = 10} = {}) {
const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
if (typeof func != "function") {
throw new TypeError();
}
if (!(typeof timeout == "number" && typeof interval == "number")) {
throw new TypeError();
}
if ((!Number.isInteger(timeout) || timeout < 0) ||
(!Number.isInteger(interval) || interval < 0)) {
throw new RangeError();
}
return new Promise((resolve, reject) => {
const start = new Date().getTime();
const end = start + timeout;
@ -136,7 +151,7 @@ function PollPromise(func, {timeout = 2000, interval = 10} = {}) {
* ``reject(error)``.
* @param {timeout=} [timeout=1500] timeout
* ``condition``'s ``reject`` callback will be called
* after this timeout.
* after this timeout, given in milliseconds.
* @param {Error=} [throws=TimeoutError] throws
* When the ``timeout`` is hit, this error class will be
* thrown. If it is null, no error is thrown and the promise is
@ -144,10 +159,25 @@ function PollPromise(func, {timeout = 2000, interval = 10} = {}) {
*
* @return {Promise.<*>}
* Timed promise.
*
* @throws {TypeError}
* If `timeout` is not a number.
* @throws {RangeError}
* If `timeout` is not an unsigned integer.
*/
function TimedPromise(fn, {timeout = 1500, throws = TimeoutError} = {}) {
const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
if (typeof fn != "function") {
throw new TypeError();
}
if (typeof timeout != "number") {
throw new TypeError();
}
if (!Number.isInteger(timeout) || timeout < 0) {
throw new RangeError();
}
return new Promise((resolve, reject) => {
// Reject only if |throws| is given. Otherwise it is assumed that
// the user is OK with the promise timing out.

Просмотреть файл

@ -2,11 +2,48 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const {PollPromise} = ChromeUtils.import("chrome://marionette/content/sync.js", {});
const {
PollPromise,
TimedPromise,
} = ChromeUtils.import("chrome://marionette/content/sync.js", {});
const DEFAULT_TIMEOUT = 2000;
add_task(async function test_PollPromise_types() {
add_test(function test_PollPromise_funcTypes() {
for (let type of ["foo", 42, null, undefined, true, [], {}]) {
Assert.throws(() => new PollPromise(type), /TypeError/);
}
new PollPromise(() => {});
new PollPromise(function() {});
run_next_test();
});
add_test(function test_PollPromise_timeoutTypes() {
for (let timeout of ["foo", null, true, [], {}]) {
Assert.throws(() => new PollPromise(() => {}, {timeout}), /TypeError/);
}
for (let timeout of [1.2, -1]) {
Assert.throws(() => new PollPromise(() => {}, {timeout}), /RangeError/);
}
new PollPromise(() => {}, {timeout: 42});
run_next_test();
});
add_test(function test_PollPromise_intervalTypes() {
for (let interval of ["foo", null, true, [], {}]) {
Assert.throws(() => new PollPromise(() => {}, {interval}), /TypeError/);
}
for (let interval of [1.2, -1]) {
Assert.throws(() => new PollPromise(() => {}, {interval}), /RangeError/);
}
new PollPromise(() => {}, {interval: 42});
run_next_test();
});
add_task(async function test_PollPromise_retvalTypes() {
for (let typ of [true, false, "foo", 42, [], {}]) {
strictEqual(typ, await new PollPromise(resolve => resolve(typ)));
}
@ -72,3 +109,25 @@ add_task(async function test_PollPromise_interval() {
}, {timeout: 100, interval: 100});
equal(2, nevals);
});
add_test(function test_TimedPromise_funcTypes() {
for (let type of ["foo", 42, null, undefined, true, [], {}]) {
Assert.throws(() => new TimedPromise(type), /TypeError/);
}
new TimedPromise(resolve => resolve());
new TimedPromise(function(resolve) { resolve(); });
run_next_test();
});
add_test(function test_TimedPromise_timeoutTypes() {
for (let timeout of ["foo", null, true, [], {}]) {
Assert.throws(() => new TimedPromise(resolve => resolve(), {timeout}), /TypeError/);
}
for (let timeout of [1.2, -1]) {
Assert.throws(() => new TimedPromise(resolve => resolve(), {timeout}), /RangeError/);
}
new TimedPromise(resolve => resolve(), {timeout: 42});
run_next_test();
});