Bug 681843 - Part 1: Clean up async.js. r=rnewman

This commit is contained in:
Philipp von Weitershausen 2011-08-26 10:25:19 -07:00
Родитель 1476288c81
Коммит beb1d69651
5 изменённых файлов: 0 добавлений и 517 удалений

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

@ -129,157 +129,6 @@ let Async = {
return callback;
},
/**
* Synchronously invoke a method that takes only a `callback` argument.
*/
callSpinningly: function callSpinningly(self, method) {
let callback = this.makeSpinningCallback();
method.call(self, callback);
return callback.wait();
},
/*
* Produce a sequence of callbacks which -- when all have been executed
* successfully *or* any have failed -- invoke the output callback.
*
* Returns a generator.
*
* Each input callback should have the signature (error, result), and should
* return a truthy value if the computation should be considered to have
* failed.
*
* The contents of ".data" on each input callback are copied to the
* resultant callback items. This can save some effort on the caller's side.
*
* These callbacks are assumed to be single- or double-valued (a "result" and
* a "context", say), which covers the common cases without the expense of
* `arguments`.
*/
barrieredCallbacks: function (callbacks, output) {
if (!output) {
throw "No output callback provided to barrieredCallbacks.";
}
let counter = callbacks.length;
function makeCb(input) {
let cb = function(error, result, context) {
if (!output) {
return;
}
let err;
try {
err = input(error, result, context);
} catch (ex) {
output(ex);
output = undefined;
return;
}
if ((0 == --counter) || err) {
output(err);
output = undefined;
}
};
cb.data = input.data;
return cb;
}
return (makeCb(i) for each (i in callbacks));
},
/*
* Similar to barrieredCallbacks, but with the same callback each time.
*/
countedCallback: function (componentCb, count, output) {
if (!output) {
throw "No output callback provided to countedCallback.";
}
if (!count || (count <= 0)) {
throw "Invalid count provided to countedCallback.";
}
let counter = count;
return function (error, result, context) {
if (!output) {
return;
}
let err;
try {
err = componentCb(error, result, context);
} catch (ex) {
output(ex);
// We're done; make sure output callback is only called once.
output = undefined;
return;
}
if ((0 == --counter) || err) {
output(err); // If this throws, then... oh well.
output = undefined;
return;
}
};
},
/*
* Invoke `f` with each item and a wrapped version of `componentCb`.
* When each component callback is invoked, the next invocation of `f` is
* begun, unless the return value is truthy. (See barrieredCallbacks.)
*
* Finally, invoke the output callback.
*
* If there are no items, the output callback is invoked immediately.
*/
serially: function serially(items, f, componentCb, output) {
if (!output) {
throw "No output callback provided to serially.";
}
if (!items || !items.length) {
output();
return;
}
let count = items.length;
let i = 0;
function cb(error, result, context) {
let err = error;
if (!err) {
try {
err = componentCb(error, result, context);
} catch (ex) {
err = ex;
}
}
if ((++i == count) || err) {
output(err);
return;
}
Utils.nextTick(function () { f(items[i], cb); });
}
f(items[i], cb);
},
/*
* Return a callback which executes `f` then `callback`, regardless of
* whether it was invoked with an error. If an exception is thrown during the
* evaluation of `f`, it takes precedence over an error provided to the
* callback.
*
* When used to wrap a callback, this offers similar behavior to try..finally
* in plain JavaScript.
*/
finallyCallback: function (callback, f) {
return function(err) {
try {
f();
callback(err);
} catch (ex) {
callback(ex);
}
};
},
// Prototype for mozIStorageCallback, used in querySpinningly.
// This allows us to define the handle* functions just once rather
// than on every querySpinningly invocation.

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

@ -202,25 +202,6 @@ let Utils = {
}
},
/*
* Partition the input array into an array of arrays. Return a generator.
*/
slices: function slices(arr, sliceSize) {
if (!sliceSize || sliceSize <= 0)
throw "Invalid slice size.";
if (sliceSize > arr.length) {
yield arr;
} else {
let offset = 0;
while (arr.length > offset) {
yield arr.slice(offset, offset + sliceSize);
offset += sliceSize;
}
}
},
byteArrayToString: function byteArrayToString(bytes) {
return [String.fromCharCode(byte) for each (byte in bytes)].join("");
},

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

@ -1,297 +0,0 @@
Cu.import("resource://services-sync/async.js");
function chain(fs) {
fs.reduce(function (prev, next) next.bind(this, prev),
run_next_test)();
}
// barrieredCallbacks.
add_test(function test_barrieredCallbacks() {
let s1called = false;
let s2called = false;
function reset() {
_(" > reset.");
s1called = s2called = false;
}
function succeed1(err, result) {
_(" > succeed1.");
s1called = true;
}
function succeed2(err, result) {
_(" > succeed2.");
s2called = true;
}
function fail1(err, result) {
_(" > fail1.");
return "failed";
}
function throw1(err, result) {
_(" > throw1.");
throw "Aieeee!";
}
function doneSequential(next, err) {
_(" > doneSequential.");
do_check_eq(err, "failed");
do_check_true(s1called);
do_check_true(s2called);
next();
}
function doneFailFirst(next, err) {
_(" > doneFailFirst.");
do_check_eq(err, "failed");
do_check_false(s1called);
do_check_false(s2called);
next();
}
function doneOnlySucceed(next, err) {
_(" > doneOnlySucceed.");
do_check_true(!err);
do_check_true(s1called);
do_check_true(s2called);
next();
}
function doneThrow(next, err) {
_(" > doneThrow.");
do_check_eq(err, "Aieeee!");
do_check_true(s1called);
do_check_false(s2called);
next();
}
function sequence_test(label, parts, end) {
return function (next) {
_("Sequence test '" + label + "':");
reset();
for (let cb in Async.barrieredCallbacks(parts, end.bind(this, next)))
cb();
};
}
chain(
[sequence_test("failFirst",
[fail1, succeed1, succeed2],
doneFailFirst),
sequence_test("sequentially",
[succeed1, succeed2, fail1],
doneSequential),
sequence_test("onlySucceed",
[succeed1, succeed2],
doneOnlySucceed),
sequence_test("throw",
[succeed1, throw1, succeed2],
doneThrow)]);
});
add_test(function test_empty_barrieredCallbacks() {
let err;
try {
Async.barrieredCallbacks([], function (err) { }).next();
} catch (ex) {
err = ex;
}
_("err is " + err);
do_check_true(err instanceof StopIteration);
run_next_test();
});
add_test(function test_no_output_barrieredCallbacks() {
let err;
try {
Async.barrieredCallbacks([function (x) {}], null);
} catch (ex) {
err = ex;
}
do_check_eq(err, "No output callback provided to barrieredCallbacks.");
run_next_test();
});
add_test(function test_serially() {
let called = {};
let i = 1;
function reset() {
called = {};
i = 0;
}
function f(x, cb) {
called[x] = ++i;
cb(null, x);
}
function err_on(expected) {
return function (err, result, context) {
if (err) {
return err;
}
if (result == expected) {
return expected;
}
_("Got " + result + ", passing.");
};
}
// Fail in the middle.
reset();
Async.serially(["a", "b", "d"], f, err_on("b"), function (err) {
do_check_eq(1, called["a"]);
do_check_eq(2, called["b"]);
do_check_false(!!called["d"]);
do_check_eq(err, "b");
// Don't fail.
reset();
Async.serially(["a", "d", "b"], f, err_on("x"), function (err) {
do_check_eq(1, called["a"]);
do_check_eq(3, called["b"]);
do_check_eq(2, called["d"]);
do_check_false(!!err);
// Empty inputs.
reset();
Async.serially([], f, err_on("a"), function (err) {
do_check_false(!!err);
reset();
Async.serially(undefined, f, err_on("a"), function (err) {
do_check_false(!!err);
run_next_test();
});
});
});
});
});
add_test(function test_countedCallback() {
let error = null;
let output = null;
let context = null;
let counter = 0;
function cb(err, result, ctx) {
counter++;
output = result;
error = err;
context = ctx;
if (err == "error!")
return "Oh dear.";
}
let c1;
c1 = Async.countedCallback(cb, 3, function (err) {
do_check_eq(2, counter);
do_check_eq("error!", error);
do_check_eq(2, output);
do_check_eq("b", context);
do_check_eq(err, "Oh dear.");
// If we call the counted callback again (once this output function is
// done, that is), then the component callback is not invoked.
Utils.nextTick(function () {
_("Don't expect component callback.");
c1("not", "running", "now");
do_check_eq(2, counter);
do_check_eq("error!", error);
do_check_eq(2, output);
do_check_eq("b", context);
run_next_test();
});
});
c1(1, "foo", "a");
do_check_eq(1, counter);
do_check_eq(1, error);
do_check_eq("foo", output);
do_check_eq("a", context);
c1("error!", 2, "b");
// Subsequent checks must now take place inside the 'done' callback... read
// above!
});
add_test(function test_finallyCallback() {
let fnCalled = false;
let cbCalled = false;
let error = undefined;
function reset() {
fnCalled = cbCalled = false;
error = undefined;
}
function fn(arg) {
do_check_false(!!arg);
fnCalled = true;
}
function fnThrow(arg) {
do_check_false(!!arg);
fnCalled = true;
throw "Foo";
}
function cb(next, err) {
_("Called with " + err);
cbCalled = true;
error = err;
next();
}
function allGood(next) {
reset();
let callback = cb.bind(this, function() {
do_check_true(fnCalled);
do_check_true(cbCalled);
do_check_false(!!error);
next();
});
Async.finallyCallback(callback, fn)(null);
}
function inboundErr(next) {
reset();
let callback = cb.bind(this, function() {
do_check_true(fnCalled);
do_check_true(cbCalled);
do_check_eq(error, "Baz");
next();
});
Async.finallyCallback(callback, fn)("Baz");
}
function throwsNoErr(next) {
reset();
let callback = cb.bind(this, function() {
do_check_true(fnCalled);
do_check_true(cbCalled);
do_check_eq(error, "Foo");
next();
});
Async.finallyCallback(callback, fnThrow)(null);
}
function throwsOverrulesErr(next) {
reset();
let callback = cb.bind(this, function() {
do_check_true(fnCalled);
do_check_true(cbCalled);
do_check_eq(error, "Foo");
next();
});
Async.finallyCallback(callback, fnThrow)("Bar");
}
chain([throwsOverrulesErr,
throwsNoErr,
inboundErr,
allGood]);
});
function run_test() {
run_next_test();
}

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

@ -1,48 +0,0 @@
Cu.import("resource://services-sync/util.js");
function run_test() {
let input = [1, 2, 3, 4, 5];
let err;
try {
Utils.slices(input, 0).next();
} catch (ex) {
err = ex;
}
do_check_eq("Invalid slice size.", err);
err = undefined;
try {
Utils.slices(input).next();
} catch (ex) {
err = ex;
}
do_check_eq("Invalid slice size.", err);
function slurp(g) [x for each (x in g)]
let sliced1 = slurp(Utils.slices(input, 1));
let sliced2 = slurp(Utils.slices(input, 2));
let sliced3 = slurp(Utils.slices(input, 5));
let sliced4 = slurp(Utils.slices(input, 7));
do_check_eq(sliced1.length, 5);
do_check_eq(sliced2.length, 3);
do_check_eq(sliced3.length, 1);
do_check_eq(sliced4.length, 1);
sliced1.every(function(x) x.length == 1);
_(JSON.stringify(sliced2));
do_check_eq(sliced2[0].length, 2);
do_check_eq(sliced2[1].length, 2);
do_check_eq(sliced2[2].length, 1);
sliced3.every(function(x) x.length == 5);
sliced4.every(function(x) x.length == 5);
let sliced5 = slurp(Utils.slices(["foo"], 50));
do_check_eq(sliced5.length, 1);
do_check_eq(sliced5[0], "foo");
let sliced6 = slurp(Utils.slices([], 50));
do_check_eq(sliced6.length, 1);
do_check_eq(sliced6[0].length, 0);
}

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

@ -4,7 +4,6 @@ tail =
[test_Observers.js]
[test_Preferences.js]
[test_async_helpers.js]
[test_async_querySpinningly.js]
[test_auth_manager.js]
[test_bookmark_batch_fail.js]
@ -126,6 +125,5 @@ skip-if = (os == "mac" && debug) || os == "android"
[test_utils_sha1.js]
[test_utils_sha1hmac.js]
[test_utils_sha256HMAC.js]
[test_utils_slices.js]
[test_utils_stackTrace.js]
[test_utils_utf8.js]