Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 80085):
* <cperivol@csail.mit.edu> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return
*
* Chris Perivolaropoulos.
* ----------------------------------------------------------------------------
*/
var assert = require('assert');
function CheckpointManager(timeout) {
this.checkpoints = {};
this.timeout = null;
this.hooks = {};
this.closed = false;
if (timeout !== null){
this.timeout = setTimeout(this.timeoutFail.bind(this), timeout || 1500);
}
}
CheckpointManager.prototype = {
timeoutFail: function () {
throw Error("TIMEOUT: Checkpoints accessed:\n" +
JSON.stringify(this.checkpoints, null, 2));
},
setCheckpoint: function (index, name) {
var cp = this.checkpoints[index] || {},
passes = (cp.passes || 0) + 1;
if (name && cp.name) {
assert.equal(name, cp.name, "Both checkpoints '" + name +
"' and '" + cp.name + "' have index " + index);
}
if (index > 1) {
assert(this.checkpoints[index - 1], "You got to checkpoint " +
index + "skipping " + index - 1);
}
this.checkpoints[index] = {passes: passes, name: name || index,
index: index};
this.triggerHook(index);
},
triggerHook: function (id) {
var checkpoint = this.getCheckpoint(id),
hook = this.hooks[checkpoint.name];
if (hook && hook.passes == checkpoint.passes) {
hook.callback();
return;
}
},
getCheckpoint: function (idOrName) {
var self = this;
return this.checkpoints[idOrName] ||
Object.getOwnPropertyNames(this.checkpoints)
.map(function (k) {return self.checkpoints[k];})
.filter(function (cp) {return cp.name == idOrName;})
.pop();
},
close: function (max, passesDict) {
var passIds = {}, self = this;
assert(!this.closed);
this.closed = true;
Object.getOwnPropertyNames(passesDict || {}).forEach(function (key) {
var cp = self.getCheckpoint(key);
if (cp) passIds[cp.index] = passesDict[key];
});
// Check that the incrementing ids were all passed.
for (var i = 0; i < (max || 0); i++) {
var expected = passIds[i] || 1;
assert(this.checkpoints[i], "Skipped checkpoint: " + i +
JSON.stringify(this.checkpoints));
}
// Check that any extra assertions form the passes dict are satisfied.
Object.getOwnPropertyNames(passesDict || {}).forEach(function (ckp) {
var cp = self.getCheckpoint(ckp) || {passes: 0, name: ckp};
assert.equal(cp.passes, passesDict[ckp],
"Checkpoint " + ckp + " accessed times: " +
cp.passes + " != " + passesDict[ckp]);
});
clearTimeout(this.timeout);
},
onCheckpoint: function (checkpoint, passes, cb) {
if (this.checkpoints[checkpoint])
throw Error("Registered checkpoint hook after checkpoints were reached.");
this.hooks[checkpoint] = {passes: passes || 1, callback: cb};
}
};
module.exports = CheckpointManager;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment