2011-12-15 15:12:54 +01:00
|
|
|
|
|
|
|
// Mock Timers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
|
|
|
|
|
|
|
;(function(){
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
/**
|
|
|
|
* Localized timer stack.
|
|
|
|
*/
|
|
|
|
var timers = [];
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
// nodejs, rhino don't have a window object
|
|
|
|
var global = this;
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
// if they where mocked before this library is loaded - bad luck
|
|
|
|
var savedGlobals = {
|
|
|
|
setTimeout: global.setTimeout,
|
|
|
|
setInterval: global.setInterval,
|
|
|
|
clearInterval: global.clearInterval,
|
|
|
|
clearTimeout: global.clearTimeout,
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
// those should not be globals, but are mocked none the less, so we save them
|
|
|
|
resetTimers: global.resetTimers,
|
|
|
|
tick: global.tick
|
|
|
|
};
|
|
|
|
var hadResetTimers = 'resetTimers' in global;
|
|
|
|
var hadTick = 'tick' in global;
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
function forEachProperty(anObject, aClosure) {
|
|
|
|
for (var key in anObject) {
|
|
|
|
if ( ! anObject.hasOwnProperty(key))
|
|
|
|
continue;
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
aClosure(key, anObject[key]);
|
|
|
|
}
|
|
|
|
}
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
global.MockTimers = {
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
mockTimersVersion: '2.0.0',
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
mockGlobalTimerFunctions: function() {
|
|
|
|
forEachProperty(this.mocks, function(aName, aFunction) {
|
|
|
|
global[aName] = aFunction;
|
|
|
|
});
|
|
|
|
},
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
unmockGlobalTimerFunctions: function() {
|
|
|
|
forEachProperty(this.savedGlobals, function(aName, aFunction) {
|
|
|
|
global[aName] = aFunction;
|
|
|
|
});
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
if ( ! hadResetTimers)
|
|
|
|
delete global['resetTimers'];
|
|
|
|
if ( ! hadTick)
|
|
|
|
delete global['tick'];
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
}
|
|
|
|
};
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
function clearTimer(id) {
|
|
|
|
return delete timers[--id];
|
|
|
|
}
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
var mocks = {
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
/**
|
|
|
|
* Set mock timeout with _callback_ and timeout of _ms_.
|
|
|
|
*
|
|
|
|
* @param {function} callback
|
|
|
|
* @param {int} ms
|
|
|
|
* @return {int}
|
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
setTimeout: function(callback, ms) {
|
|
|
|
var id;
|
|
|
|
return id = setInterval(function(){
|
|
|
|
callback();
|
|
|
|
clearInterval(id);
|
|
|
|
}, ms);
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set mock interval with _callback_ and interval of _ms_.
|
|
|
|
*
|
|
|
|
* @param {function} callback
|
|
|
|
* @param {int} ms
|
|
|
|
* @return {int}
|
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
setInterval: function(callback, ms) {
|
|
|
|
// REFACT: use wrapper object so callback is not changed -> state leak
|
|
|
|
callback.step = ms;
|
|
|
|
callback.current = callback.last = 0;
|
|
|
|
timers[timers.length] = callback;
|
|
|
|
return timers.length;
|
|
|
|
},
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
/**
|
|
|
|
* Destroy timer with _id_.
|
|
|
|
*
|
|
|
|
* @param {int} id
|
|
|
|
* @return {bool}
|
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
clearInterval: clearTimer,
|
|
|
|
clearTimeout: clearTimer
|
|
|
|
};
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
// additional functions that are not originally in the global namespace
|
|
|
|
/**
|
|
|
|
* Reset timers.
|
|
|
|
*
|
|
|
|
* @return {array}
|
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
mocks.resetTimers = function() {
|
|
|
|
return timers = [];
|
|
|
|
};
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
/**
|
|
|
|
* Increment each timers internal clock by _ms_.
|
|
|
|
*
|
|
|
|
* @param {int} ms
|
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
mocks.tick = function(ms) {
|
|
|
|
for (var i = 0, len = timers.length; i < len; ++i) {
|
|
|
|
if ( ! timers[i] || ! (timers[i].current += ms))
|
|
|
|
continue;
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
if (timers[i].current - timers[i].last < timers[i].step)
|
|
|
|
continue;
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step);
|
|
|
|
var remainder = (timers[i].current - timers[i].last) % timers[i].step;
|
|
|
|
timers[i].last = timers[i].current - remainder;
|
|
|
|
while (times-- && timers[i])
|
|
|
|
timers[i]();
|
|
|
|
}
|
|
|
|
};
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
// make them available publicly
|
|
|
|
MockTimers.mocks = mocks;
|
2016-01-06 00:34:58 +01:00
|
|
|
|
2011-12-15 15:12:54 +01:00
|
|
|
JSpec.include({
|
|
|
|
beforeSpec: function(){
|
|
|
|
MockTimers.mockGlobalTimerFunctions();
|
|
|
|
},
|
|
|
|
afterSpec : function() {
|
|
|
|
MockTimers.unmockGlobalTimerFunctions();
|
|
|
|
}
|
|
|
|
});
|
2016-01-06 00:34:58 +01:00
|
|
|
})();
|