lib/jspec.timers.js in jspec-4.3.2 vs lib/jspec.timers.js in jspec-4.3.3

- old
+ new

@@ -1,90 +1,154 @@ -// JSpec - Mock Timers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed) +// Mock Timers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed) ;(function(){ /** - * Version. - */ - - mockTimersVersion = '1.0.2' - - /** * Localized timer stack. */ + var timers = []; - var timers = [] + // nodejs, rhino don't have a window object + var global = this; - /** - * Set mock timeout with _callback_ and timeout of _ms_. - * - * @param {function} callback - * @param {int} ms - * @return {int} - * @api public - */ + // 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, + + // 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; - setTimeout = function(callback, ms) { - var id - return id = setInterval(function(){ - callback() - clearInterval(id) - }, ms) + function forEachProperty(anObject, aClosure) { + for (var key in anObject) { + if ( ! anObject.hasOwnProperty(key)) + continue; + + aClosure(key, anObject[key]); + } } - /** - * Set mock interval with _callback_ and interval of _ms_. - * - * @param {function} callback - * @param {int} ms - * @return {int} - * @api public - */ - - setInterval = function(callback, ms) { - callback.step = ms, callback.current = callback.last = 0 - return timers[timers.length] = callback, timers.length + global.MockTimers = { + + mockTimersVersion: '2.0.0', + + mockGlobalTimerFunctions: function() { + forEachProperty(this.mocks, function(aName, aFunction) { + global[aName] = aFunction; + }); + }, + + unmockGlobalTimerFunctions: function() { + forEachProperty(this.savedGlobals, function(aName, aFunction) { + global[aName] = aFunction; + }); + + if ( ! hadResetTimers) + delete global['resetTimers']; + if ( ! hadTick) + delete global['tick']; + + } + }; + + function clearTimer(id) { + return delete timers[--id]; } - /** - * Destroy timer with _id_. - * - * @param {int} id - * @return {bool} - * @api public - */ + var mocks = { + + /** + * 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); + }, - clearInterval = clearTimeout = function(id) { - return delete timers[--id] - } + + /** + * 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; + }, + + /** + * Destroy timer with _id_. + * + * @param {int} id + * @return {bool} + * @api public + */ + clearInterval: clearTimer, + clearTimeout: clearTimer + }; + // additional functions that are not originally in the global namespace /** * Reset timers. * * @return {array} * @api public */ + mocks.resetTimers = function() { + return timers = []; + }; - resetTimers = function() { - return timers = [] - } - /** * 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; + + if (timers[i].current - timers[i].last < timers[i].step) + continue; + + 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](); + } + }; - tick = function(ms) { - for (var i = 0, len = timers.length; i < len; ++i) - if (timers[i] && (timers[i].current += ms)) - if (timers[i].current - timers[i].last >= timers[i].step) { - 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]() - } - } + // make them available publicly + MockTimers.mocks = mocks; -})() + JSpec.include({ + beforeSpec: function(){ + MockTimers.mockGlobalTimerFunctions(); + }, + afterSpec : function() { + MockTimers.unmockGlobalTimerFunctions(); + } + }); +})(); \ No newline at end of file