1 // Mock setTimeout, clearTimeout
  2 // Contributed by Pivotal Computer Systems, www.pivotalsf.com
  3 
  4 jasmine.FakeTimer = function() {
  5   this.reset();
  6 
  7   var self = this;
  8   self.setTimeout = function(funcToCall, millis) {
  9     self.timeoutsMade++;
 10     self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
 11     return self.timeoutsMade;
 12   };
 13 
 14   self.setInterval = function(funcToCall, millis) {
 15     self.timeoutsMade++;
 16     self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
 17     return self.timeoutsMade;
 18   };
 19 
 20   self.clearTimeout = function(timeoutKey) {
 21     self.scheduledFunctions[timeoutKey] = undefined;
 22   };
 23 
 24   self.clearInterval = function(timeoutKey) {
 25     self.scheduledFunctions[timeoutKey] = undefined;
 26   };
 27 
 28 };
 29 
 30 jasmine.FakeTimer.prototype.reset = function() {
 31   this.timeoutsMade = 0;
 32   this.scheduledFunctions = {};
 33   this.nowMillis = 0;
 34 };
 35 
 36 jasmine.FakeTimer.prototype.tick = function(millis) {
 37   var oldMillis = this.nowMillis;
 38   var newMillis = oldMillis + millis;
 39   this.runFunctionsWithinRange(oldMillis, newMillis);
 40   this.nowMillis = newMillis;
 41 };
 42 
 43 jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
 44   var scheduledFunc;
 45   var funcsToRun = [];
 46   for (var timeoutKey in this.scheduledFunctions) {
 47     scheduledFunc = this.scheduledFunctions[timeoutKey];
 48     if (scheduledFunc != undefined &&
 49         scheduledFunc.runAtMillis >= oldMillis &&
 50         scheduledFunc.runAtMillis <= nowMillis) {
 51       funcsToRun.push(scheduledFunc);
 52       this.scheduledFunctions[timeoutKey] = undefined;
 53     }
 54   }
 55 
 56   if (funcsToRun.length > 0) {
 57     funcsToRun.sort(function(a, b) {
 58       return a.runAtMillis - b.runAtMillis;
 59     });
 60     for (var i = 0; i < funcsToRun.length; ++i) {
 61       try {
 62         var funcToRun = funcsToRun[i];
 63         this.nowMillis = funcToRun.runAtMillis;
 64         funcToRun.funcToCall();
 65         if (funcToRun.recurring) {
 66           this.scheduleFunction(funcToRun.timeoutKey,
 67             funcToRun.funcToCall,
 68             funcToRun.millis,
 69             true);
 70         }
 71       } catch(e) {
 72       }
 73     }
 74     this.runFunctionsWithinRange(oldMillis, nowMillis);
 75   }
 76 };
 77 
 78 jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
 79   this.scheduledFunctions[timeoutKey] = {
 80     runAtMillis: this.nowMillis + millis,
 81     funcToCall: funcToCall,
 82     recurring: recurring,
 83     timeoutKey: timeoutKey,
 84     millis: millis
 85   };
 86 };
 87 
 88 
 89 jasmine.Clock = {
 90   defaultFakeTimer: new jasmine.FakeTimer(),
 91 
 92   reset: function() {
 93     jasmine.Clock.assertInstalled();
 94     jasmine.Clock.defaultFakeTimer.reset();
 95   },
 96 
 97   tick: function(millis) {
 98     jasmine.Clock.assertInstalled();
 99     jasmine.Clock.defaultFakeTimer.tick(millis);
100   },
101 
102   runFunctionsWithinRange: function(oldMillis, nowMillis) {
103     jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
104   },
105 
106   scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
107     jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
108   },
109 
110   useMock: function() {
111     var spec = jasmine.getEnv().currentSpec;
112     spec.after(jasmine.Clock.uninstallMock);
113 
114     jasmine.Clock.installMock();
115   },
116 
117   installMock: function() {
118     jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
119   },
120 
121   uninstallMock: function() {
122     jasmine.Clock.assertInstalled();
123     jasmine.Clock.installed = jasmine.Clock.real;
124   },
125 
126   real: {
127     setTimeout: window.setTimeout,
128     clearTimeout: window.clearTimeout,
129     setInterval: window.setInterval,
130     clearInterval: window.clearInterval
131   },
132 
133   assertInstalled: function() {
134     if (jasmine.Clock.installed != jasmine.Clock.defaultFakeTimer) {
135       throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
136     }
137   },  
138 
139   installed: null
140 };
141 jasmine.Clock.installed = jasmine.Clock.real;
142 
143 window.setTimeout = function(funcToCall, millis) {
144   return jasmine.Clock.installed.setTimeout.apply(this, arguments);
145 };
146 
147 window.setInterval = function(funcToCall, millis) {
148   return jasmine.Clock.installed.setInterval.apply(this, arguments);
149 };
150 
151 window.clearTimeout = function(timeoutKey) {
152   return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
153 };
154 
155 window.clearInterval = function(timeoutKey) {
156   return jasmine.Clock.installed.clearInterval.apply(this, arguments);
157 };
158 
159