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] = jasmine.undefined;
 22   };
 23 
 24   self.clearInterval = function(timeoutKey) {
 25     self.scheduledFunctions[timeoutKey] = jasmine.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 != jasmine.undefined &&
 49         scheduledFunc.runAtMillis >= oldMillis &&
 50         scheduledFunc.runAtMillis <= nowMillis) {
 51       funcsToRun.push(scheduledFunc);
 52       this.scheduledFunctions[timeoutKey] = jasmine.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  * @namespace
 90  */
 91 jasmine.Clock = {
 92   defaultFakeTimer: new jasmine.FakeTimer(),
 93 
 94   reset: function() {
 95     jasmine.Clock.assertInstalled();
 96     jasmine.Clock.defaultFakeTimer.reset();
 97   },
 98 
 99   tick: function(millis) {
100     jasmine.Clock.assertInstalled();
101     jasmine.Clock.defaultFakeTimer.tick(millis);
102   },
103 
104   runFunctionsWithinRange: function(oldMillis, nowMillis) {
105     jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
106   },
107 
108   scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
109     jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
110   },
111 
112   useMock: function() {
113     var spec = jasmine.getEnv().currentSpec;
114     spec.after(jasmine.Clock.uninstallMock);
115 
116     jasmine.Clock.installMock();
117   },
118 
119   installMock: function() {
120     jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
121   },
122 
123   uninstallMock: function() {
124     jasmine.Clock.assertInstalled();
125     jasmine.Clock.installed = jasmine.Clock.real;
126   },
127 
128   real: {
129     setTimeout: jasmine.getGlobal().setTimeout,
130     clearTimeout: jasmine.getGlobal().clearTimeout,
131     setInterval: jasmine.getGlobal().setInterval,
132     clearInterval: jasmine.getGlobal().clearInterval
133   },
134 
135   assertInstalled: function() {
136     if (jasmine.Clock.installed != jasmine.Clock.defaultFakeTimer) {
137       throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
138     }
139   },
140 
141   installed: null
142 };
143 jasmine.Clock.installed = jasmine.Clock.real;
144 
145 //else for IE support
146 jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
147   if (jasmine.Clock.installed.setTimeout.apply) {
148     return jasmine.Clock.installed.setTimeout.apply(this, arguments);
149   } else {
150     return jasmine.Clock.installed.setTimeout(funcToCall, millis);
151   }
152 };
153 
154 jasmine.getGlobal().setInterval = function(funcToCall, millis) {
155   if (jasmine.Clock.installed.setInterval.apply) {
156     return jasmine.Clock.installed.setInterval.apply(this, arguments);
157   } else {
158     return jasmine.Clock.installed.setInterval(funcToCall, millis);
159   }
160 };
161 
162 jasmine.getGlobal().clearTimeout = function(timeoutKey) {
163   if (jasmine.Clock.installed.clearTimeout.apply) {
164     return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
165   } else {
166     return jasmine.Clock.installed.clearTimeout(timeoutKey);
167   }
168 };
169 
170 jasmine.getGlobal().clearInterval = function(timeoutKey) {
171   if (jasmine.Clock.installed.clearTimeout.apply) {
172     return jasmine.Clock.installed.clearInterval.apply(this, arguments);
173   } else {
174   return jasmine.Clock.installed.clearInterval(timeoutKey);
175   }
176 };
177 
178