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     if (!jasmine.Clock.isInstalled()) {
114       var spec = jasmine.getEnv().currentSpec;
115       spec.after(jasmine.Clock.uninstallMock);
116 
117       jasmine.Clock.installMock();
118     }
119   },
120 
121   installMock: function() {
122     jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
123   },
124 
125   uninstallMock: function() {
126     jasmine.log("uninstall")
127     jasmine.Clock.assertInstalled();
128     jasmine.Clock.installed = jasmine.Clock.real;
129   },
130 
131   real: {
132     setTimeout: jasmine.getGlobal().setTimeout,
133     clearTimeout: jasmine.getGlobal().clearTimeout,
134     setInterval: jasmine.getGlobal().setInterval,
135     clearInterval: jasmine.getGlobal().clearInterval
136   },
137 
138   assertInstalled: function() {
139     if (!jasmine.Clock.isInstalled()) {
140       throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
141     }
142   },
143 
144   isInstalled: function() {
145     return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
146   },
147 
148   installed: null
149 };
150 jasmine.Clock.installed = jasmine.Clock.real;
151 
152 //else for IE support
153 jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
154   if (jasmine.Clock.installed.setTimeout.apply) {
155     return jasmine.Clock.installed.setTimeout.apply(this, arguments);
156   } else {
157     return jasmine.Clock.installed.setTimeout(funcToCall, millis);
158   }
159 };
160 
161 jasmine.getGlobal().setInterval = function(funcToCall, millis) {
162   if (jasmine.Clock.installed.setInterval.apply) {
163     return jasmine.Clock.installed.setInterval.apply(this, arguments);
164   } else {
165     return jasmine.Clock.installed.setInterval(funcToCall, millis);
166   }
167 };
168 
169 jasmine.getGlobal().clearTimeout = function(timeoutKey) {
170   if (jasmine.Clock.installed.clearTimeout.apply) {
171     return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
172   } else {
173     return jasmine.Clock.installed.clearTimeout(timeoutKey);
174   }
175 };
176 
177 jasmine.getGlobal().clearInterval = function(timeoutKey) {
178   if (jasmine.Clock.installed.clearTimeout.apply) {
179     return jasmine.Clock.installed.clearInterval.apply(this, arguments);
180   } else {
181     return jasmine.Clock.installed.clearInterval(timeoutKey);
182   }
183 };
184 
185