UNPKG

zurvan

Version:

A library for simulating time in Node.js

155 lines (127 loc) 3.9 kB
'use strict'; var FieldOverrider = require('./utils/FieldOverrider'); var TimerRepository = require('./TimerRepository'); var TypeChecks = require('./utils/TypeChecks'); function Callback(f, args) { this.f = f; this.args = args; } Callback.prototype.call = function() { this.f.apply(undefined, this.args); }; function TimerInterceptor(timeServer, timerType) { this.timeServer = timeServer; this.timerType = timerType; } TimerInterceptor.prototype.intercept = function(config, uidGenerator) { this.config = config; this.timerRepository = new TimerRepository(this.config, uidGenerator); this.setTimers = new FieldOverrider( this.timerType.context, this.timerType.setName, this.addTimer.bind(this, this.timerType.type) ); this.clearTimers = new FieldOverrider( this.timerType.context, this.timerType.clearName, this.clearTimer.bind(this) ); if (this.config.fakeNodeDedicatedTimers) { var nodeTimers = require('timers'); this._nodeSetterOverrider = new FieldOverrider( nodeTimers, this.timerType.setName, this.addTimer.bind(this, this.timerType.type) ); this._nodeClearerOverrider = new FieldOverrider( nodeTimers, this.timerType.clearName, this.clearTimer.bind(this) ); } }; TimerInterceptor.prototype.release = function() { this.setTimers.restore(); this.clearTimers.restore(); if (this.config.fakeNodeDedicatedTimers) { this._nodeSetterOverrider.restore(); this._nodeClearerOverrider.restore(); } return this.timerRepository.releaseAll(); }; TimerInterceptor.prototype.nextTimers = function() { return this.timerRepository.nextTimers(); }; TimerInterceptor.prototype.lastTimer = function() { return this.timerRepository.lastTimer(); }; TimerInterceptor.prototype.createCallback = function(callback, args) { if (TypeChecks.isFunction(callback)) { return new Callback(callback, args); } if (this.config.acceptEvalTimers) { return new Callback(function() { /*jshint -W061 */ return eval(callback); }, []); } throw new Error( 'Node.js does not accept strings to be evaluated in timers. If you wish, you can configure Zurvan to use them, but beware.' ); }; var MINIMUM_CALL_DELAY = 1; var MAX_CALL_DELAY = Math.pow(2, 31) - 1; // int32 boundary function timerCreateErrorMessage(mustBe, given) { return ( 'Call delay in timer call must be ' + mustBe + ' given: << ' + given + ' >>' ); } TimerInterceptor.prototype.createCallDelay = function(requestedCallDelay) { if (!TypeChecks.isNumber(requestedCallDelay)) { if (this.config.denyImplicitTimer) { throw new Error( timerCreateErrorMessage('a numeric value', requestedCallDelay) ); } return MINIMUM_CALL_DELAY; } if (requestedCallDelay < MINIMUM_CALL_DELAY) { if (this.config.denyTimersShorterThan1Ms) { throw new Error( timerCreateErrorMessage('>= ' + MINIMUM_CALL_DELAY, requestedCallDelay) ); } return MINIMUM_CALL_DELAY; } if (requestedCallDelay > MAX_CALL_DELAY) { if (this.config.denyTimersLongerThanInt32) { throw new Error( timerCreateErrorMessage('<= ' + MAX_CALL_DELAY, requestedCallDelay) ); } return MINIMUM_CALL_DELAY; } return requestedCallDelay; }; TimerInterceptor.prototype.addTimer = function( TimerType, requestedCallback, requestedCallDelay ) { var callback = this.createCallback( requestedCallback, [].splice.call(arguments, 3) ); var callDelay = this.createCallDelay(requestedCallDelay); var timer = new TimerType( callback, this.timerRepository, this.timeServer.currentTime, callDelay ); return this.timerRepository.insertTimer(timer); }; TimerInterceptor.prototype.clearTimer = function(uid) { return this.timerRepository.clearTimer(uid); }; module.exports = TimerInterceptor;