upgrade to angular 0.9.10 and update the code with angular API changes
[angular-drzb] / test / lib / angular / angular-mocks.js
1 /**
2  * The MIT License
3  *
4  * Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25
26 /*
27
28  NUGGGGGH MUST TONGUE WANGS
29                            \
30                                 .....
31                                C C  /
32                               /<   /
33                ___ __________/_#__=o
34               /(- /(\_\________   \
35               \ ) \ )_      \o     \
36               /|\ /|\       |'     |
37                             |     _|
38                             /o   __\
39                            / '     |
40                           / /      |
41                          /_/\______|
42                         (   _(    <
43                          \    \    \
44                           \    \    |
45                            \____\____\
46                            ____\_\__\_\
47                          /`   /`     o\
48                          |___ |_______|.. . b'ger
49
50
51  IN THE FINAL BUILD THIS FILE DOESN'T HAVE DIRECT ACCESS TO GLOBAL FUNCTIONS
52  DEFINED IN Angular.js YOU *MUST* REFER TO THEM VIA angular OBJECT
53  (e.g. angular.forEach(...)) AND MAKE SURE THAT THE GIVEN FUNCTION IS EXPORTED
54  TO THE angular NAMESPACE in AngularPublic.js
55
56  */
57
58
59 /**
60  * @ngdoc overview
61  * @name angular.mock
62  * @namespace Namespace for all built-in angular mocks.
63  *
64  * @description
65  * `angular.mock` is a namespace for all built-in mocks that ship with angular and automatically
66  * replace real services if `angular-mocks.js` file is loaded after `angular.js` and before any
67  * tests.
68  */
69 angular.mock = {};
70
71
72 /**
73  * @workInProgress
74  * @ngdoc service
75  * @name angular.mock.service.$browser
76  */
77 function MockBrowser() {
78   var self = this,
79       expectations = {},
80       requests = [];
81
82   this.isMock = true;
83   self.url = "http://server";
84   self.lastUrl = self.url; // used by url polling fn
85   self.pollFns = [];
86
87
88   // register url polling fn
89
90   self.onHashChange = function(listener) {
91     self.pollFns.push(
92       function() {
93         if (self.lastUrl != self.url) {
94           listener();
95         }
96       }
97     );
98
99     return listener;
100   };
101
102
103   self.xhr = function(method, url, data, callback) {
104     if (angular.isFunction(data)) {
105       callback = data;
106       data = null;
107     }
108     if (data && angular.isObject(data)) data = angular.toJson(data);
109     if (data && angular.isString(data)) url += "|" + data;
110     var expect = expectations[method] || {};
111     var response = expect[url];
112     if (!response) {
113       throw {
114         message: "Unexpected request for method '" + method + "' and url '" + url + "'.",
115         name: "Unexpected Request"
116       };
117     }
118     requests.push(function(){
119       callback(response.code, response.response);
120     });
121   };
122   self.xhr.expectations = expectations;
123   self.xhr.requests = requests;
124   self.xhr.expect = function(method, url, data) {
125     if (data && angular.isObject(data)) data = angular.toJson(data);
126     if (data && angular.isString(data)) url += "|" + data;
127     var expect = expectations[method] || (expectations[method] = {});
128     return {
129       respond: function(code, response) {
130         if (!angular.isNumber(code)) {
131           response = code;
132           code = 200;
133         }
134         expect[url] = {code:code, response:response};
135       }
136     };
137   };
138   self.xhr.expectGET    = angular.bind(self, self.xhr.expect, 'GET');
139   self.xhr.expectPOST   = angular.bind(self, self.xhr.expect, 'POST');
140   self.xhr.expectDELETE = angular.bind(self, self.xhr.expect, 'DELETE');
141   self.xhr.expectPUT    = angular.bind(self, self.xhr.expect, 'PUT');
142   self.xhr.expectJSON   = angular.bind(self, self.xhr.expect, 'JSON');
143   self.xhr.flush = function() {
144     while(requests.length) {
145       requests.pop()();
146     }
147   };
148
149   self.cookieHash = {};
150   self.lastCookieHash = {};
151   self.deferredFns = [];
152
153   self.defer = function(fn) {
154     self.deferredFns.push(fn);
155   };
156
157   self.defer.flush = function() {
158     while (self.deferredFns.length) self.deferredFns.shift()();
159   };
160 }
161 MockBrowser.prototype = {
162
163   poll: function poll(){
164     angular.forEach(this.pollFns, function(pollFn){
165       pollFn();
166     });
167   },
168
169   addPollFn: function(pollFn) {
170     this.pollFns.push(pollFn);
171     return pollFn;
172   },
173
174   hover: function(onHover) {
175   },
176
177   getUrl: function(){
178     return this.url;
179   },
180
181   setUrl: function(url){
182     this.url = url;
183   },
184
185   cookies:  function(name, value) {
186     if (name) {
187       if (value == undefined) {
188         delete this.cookieHash[name];
189       } else {
190         if (angular.isString(value) &&       //strings only
191             value.length <= 4096) {          //strict cookie storage limits
192           this.cookieHash[name] = value;
193         }
194       }
195     } else {
196       if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
197         this.lastCookieHash = angular.copy(this.cookieHash);
198         this.cookieHash = angular.copy(this.cookieHash);
199       }
200       return this.cookieHash;
201     }
202   }
203 };
204
205 angular.service('$browser', function(){
206   return new MockBrowser();
207 });
208
209
210 /**
211  * @workInProgress
212  * @ngdoc service
213  * @name angular.mock.service.$exceptionHandler
214  *
215  * @description
216  * Mock implementation of {@link angular.service.$exceptionHandler} that rethrows any error passed
217  * into `$exceptionHandler`. If any errors are are passed into the handler in tests, it typically
218  * means that there is a bug in the application or test, so this mock will make these tests fail.
219  *
220  * See {@link angular.mock} for more info on angular mocks.
221  */
222 angular.service('$exceptionHandler', function(e) {
223   return function(e) {throw e;};
224 });
225
226
227 /**
228  * @workInProgress
229  * @ngdoc service
230  * @name angular.mock.service.$log
231  *
232  * @description
233  * Mock implementation of {@link angular.service.$log} that gathers all logged messages in arrays
234  * (one array per logging level). These arrays are exposed as `logs` property of each of the
235  * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
236  *
237  * See {@link angular.mock} for more info on angular mocks.
238  */
239 angular.service('$log', function() {
240   var $log = {
241     log: function(){ $log.logs.push(arguments) },
242     warn: function(){ $log.logs.push(arguments) },
243     info: function(){ $log.logs.push(arguments) },
244     error: function(){ $log.logs.push(arguments) }
245   };
246
247   $log.log.logs = [];
248   $log.warn.logs = [];
249   $log.info.logs = [];
250   $log.error.logs = [];
251
252   return $log;
253 });
254
255
256 /**
257  * Mock of the Date type which has its timezone specified via constroctor arg.
258  *
259  * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
260  * offset, so that we can test code that depends on local timezone settings without dependency on
261  * the time zone settings of the machine where the code is running.
262  *
263  * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
264  * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
265  *
266  * @example
267  * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
268  * newYearInBratislava.getTimezoneOffset() => -60;
269  * newYearInBratislava.getFullYear() => 2010;
270  * newYearInBratislava.getMonth() => 0;
271  * newYearInBratislava.getDate() => 1;
272  * newYearInBratislava.getHours() => 0;
273  * newYearInBratislava.getMinutes() => 0;
274  *
275  *
276  * !!!! WARNING !!!!!
277  * This is not a complete Date object so only methods that were implemented can be called safely.
278  * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
279  *
280  * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
281  * incomplete we might be missing some non-standard methods. This can result in errors like:
282  * "Date.prototype.foo called on incompatible Object".
283  */
284 function TzDate(offset, timestamp) {
285   if (angular.isString(timestamp)) {
286     var tsStr = timestamp;
287
288     this.origDate = angular.String.toDate(timestamp);
289
290     timestamp = this.origDate.getTime();
291     if (isNaN(timestamp))
292       throw {
293         name: "Illegal Argument",
294         message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
295       };
296   } else {
297     this.origDate = new Date(timestamp);
298   }
299
300   var localOffset = new Date(timestamp).getTimezoneOffset();
301   this.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
302   this.date = new Date(timestamp + this.offsetDiff);
303
304   this.getTime = function() {
305     return this.date.getTime() - this.offsetDiff;
306   };
307
308   this.toLocaleDateString = function() {
309     return this.date.toLocaleDateString();
310   };
311
312   this.getFullYear = function() {
313     return this.date.getFullYear();
314   };
315
316   this.getMonth = function() {
317     return this.date.getMonth();
318   };
319
320   this.getDate = function() {
321     return this.date.getDate();
322   };
323
324   this.getHours = function() {
325     return this.date.getHours();
326   };
327
328   this.getMinutes = function() {
329     return this.date.getMinutes();
330   };
331
332   this.getSeconds = function() {
333     return this.date.getSeconds();
334   };
335
336   this.getTimezoneOffset = function() {
337     return offset * 60;
338   };
339
340   this.getUTCFullYear = function() {
341     return this.origDate.getUTCFullYear();
342   };
343
344   this.getUTCMonth = function() {
345     return this.origDate.getUTCMonth();
346   };
347
348   this.getUTCDate = function() {
349     return this.origDate.getUTCDate();
350   };
351
352   this.getUTCHours = function() {
353     return this.origDate.getUTCHours();
354   };
355
356   this.getUTCMinutes = function() {
357     return this.origDate.getUTCMinutes();
358   };
359
360   this.getUTCSeconds = function() {
361     return this.origDate.getUTCSeconds();
362   };
363
364
365   //hide all methods not implemented in this mock that the Date prototype exposes
366   var unimplementedMethods = ['getDay', 'getMilliseconds', 'getTime', 'getUTCDay',
367       'getUTCMilliseconds', 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
368       'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
369       'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
370       'setYear', 'toDateString', 'toJSON', 'toGMTString', 'toLocaleFormat', 'toLocaleString',
371       'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
372
373   angular.forEach(unimplementedMethods, function(methodName) {
374     this[methodName] = function() {
375       throw {
376         name: "MethodNotImplemented",
377         message: "Method '" + methodName + "' is not implemented in the TzDate mock"
378       };
379     };
380   });
381 }
382
383 //make "tzDateInstance instanceof Date" return true
384 TzDate.prototype = Date.prototype;