merge: Local testing info. (ibolmo/mootools-core#18)
[mootools.git] / Tests / Utilities / sinon.js
blob2bd5c0c232fd8b1f12caa5c4c1fef82bfe788486
2 /**
3  * Sinon.JS 1.8.3, 2014/03/04
4  *
5  * @author Christian Johansen (christian@cjohansen.no)
6  * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
7  *
8  * (The BSD License)
9  * 
10  * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
11  * All rights reserved.
12  * 
13  * Redistribution and use in source and binary forms, with or without modification,
14  * are permitted provided that the following conditions are met:
15  * 
16  *     * Redistributions of source code must retain the above copyright notice,
17  *       this list of conditions and the following disclaimer.
18  *     * Redistributions in binary form must reproduce the above copyright notice,
19  *       this list of conditions and the following disclaimer in the documentation
20  *       and/or other materials provided with the distribution.
21  *     * Neither the name of Christian Johansen nor the names of his contributors
22  *       may be used to endorse or promote products derived from this software
23  *       without specific prior written permission.
24  * 
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
37 /*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
38 /**
39  * Helps IE run the fake timers. By defining global functions, IE allows
40  * them to be overwritten at a later point. If these are not defined like
41  * this, overwriting them will result in anything from an exception to browser
42  * crash.
43  *
44  * If you don't require fake timers to work in IE, don't include this file.
45  *
46  * @author Christian Johansen (christian@cjohansen.no)
47  * @license BSD
48  *
49  * Copyright (c) 2010-2013 Christian Johansen
50  */
51 function setTimeout() {}
52 function clearTimeout() {}
53 function setImmediate() {}
54 function clearImmediate() {}
55 function setInterval() {}
56 function clearInterval() {}
57 function Date() {}
59 // Reassign the original functions. Now their writable attribute
60 // should be true. Hackish, I know, but it works.
61 setTimeout = sinon.timers.setTimeout;
62 clearTimeout = sinon.timers.clearTimeout;
63 setImmediate = sinon.timers.setImmediate;
64 clearImmediate = sinon.timers.clearImmediate;
65 setInterval = sinon.timers.setInterval;
66 clearInterval = sinon.timers.clearInterval;
67 Date = sinon.timers.Date;
69 /*global sinon*/
70 /**
71  * Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows
72  * them to be overwritten at a later point. If these are not defined like
73  * this, overwriting them will result in anything from an exception to browser
74  * crash.
75  *
76  * If you don't require fake XHR to work in IE, don't include this file.
77  *
78  * @author Christian Johansen (christian@cjohansen.no)
79  * @license BSD
80  *
81  * Copyright (c) 2010-2013 Christian Johansen
82  */
83 function XMLHttpRequest() {}
85 // Reassign the original function. Now its writable attribute
86 // should be true. Hackish, I know, but it works.
87 XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
90 /**
91  * Sinon.JS 1.8.3, 2014/03/04
92  *
93  * @author Christian Johansen (christian@cjohansen.no)
94  * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
95  *
96  * (The BSD License)
97  * 
98  * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
99  * All rights reserved.
100  * 
101  * Redistribution and use in source and binary forms, with or without modification,
102  * are permitted provided that the following conditions are met:
103  * 
104  *     * Redistributions of source code must retain the above copyright notice,
105  *       this list of conditions and the following disclaimer.
106  *     * Redistributions in binary form must reproduce the above copyright notice,
107  *       this list of conditions and the following disclaimer in the documentation
108  *       and/or other materials provided with the distribution.
109  *     * Neither the name of Christian Johansen nor the names of his contributors
110  *       may be used to endorse or promote products derived from this software
111  *       without specific prior written permission.
112  * 
113  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
114  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
115  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
116  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
117  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
118  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
119  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
120  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
121  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
122  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
123  */
125 this.sinon = (function () {
126 var samsam, formatio;
127 function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else { formatio = fn(samsam); } }
128 define.amd = true;
129 ((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
130  (typeof module === "object" &&
131       function (m) { module.exports = m(); }) || // Node
132  function (m) { this.samsam = m(); } // Browser globals
133 )(function () {
134     var o = Object.prototype;
135     var div = typeof document !== "undefined" && document.createElement("div");
137     function isNaN(value) {
138         // Unlike global isNaN, this avoids type coercion
139         // typeof check avoids IE host object issues, hat tip to
140         // lodash
141         var val = value; // JsLint thinks value !== value is "weird"
142         return typeof value === "number" && value !== val;
143     }
145     function getClass(value) {
146         // Returns the internal [[Class]] by calling Object.prototype.toString
147         // with the provided value as this. Return value is a string, naming the
148         // internal class, e.g. "Array"
149         return o.toString.call(value).split(/[ \]]/)[1];
150     }
152     /**
153      * @name samsam.isArguments
154      * @param Object object
155      *
156      * Returns ``true`` if ``object`` is an ``arguments`` object,
157      * ``false`` otherwise.
158      */
159     function isArguments(object) {
160         if (typeof object !== "object" || typeof object.length !== "number" ||
161                 getClass(object) === "Array") {
162             return false;
163         }
164         if (typeof object.callee == "function") { return true; }
165         try {
166             object[object.length] = 6;
167             delete object[object.length];
168         } catch (e) {
169             return true;
170         }
171         return false;
172     }
174     /**
175      * @name samsam.isElement
176      * @param Object object
177      *
178      * Returns ``true`` if ``object`` is a DOM element node. Unlike
179      * Underscore.js/lodash, this function will return ``false`` if ``object``
180      * is an *element-like* object, i.e. a regular object with a ``nodeType``
181      * property that holds the value ``1``.
182      */
183     function isElement(object) {
184         if (!object || object.nodeType !== 1 || !div) { return false; }
185         try {
186             object.appendChild(div);
187             object.removeChild(div);
188         } catch (e) {
189             return false;
190         }
191         return true;
192     }
194     /**
195      * @name samsam.keys
196      * @param Object object
197      *
198      * Return an array of own property names.
199      */
200     function keys(object) {
201         var ks = [], prop;
202         for (prop in object) {
203             if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
204         }
205         return ks;
206     }
208     /**
209      * @name samsam.isDate
210      * @param Object value
211      *
212      * Returns true if the object is a ``Date``, or *date-like*. Duck typing
213      * of date objects work by checking that the object has a ``getTime``
214      * function whose return value equals the return value from the object's
215      * ``valueOf``.
216      */
217     function isDate(value) {
218         return typeof value.getTime == "function" &&
219             value.getTime() == value.valueOf();
220     }
222     /**
223      * @name samsam.isNegZero
224      * @param Object value
225      *
226      * Returns ``true`` if ``value`` is ``-0``.
227      */
228     function isNegZero(value) {
229         return value === 0 && 1 / value === -Infinity;
230     }
232     /**
233      * @name samsam.equal
234      * @param Object obj1
235      * @param Object obj2
236      *
237      * Returns ``true`` if two objects are strictly equal. Compared to
238      * ``===`` there are two exceptions:
239      *
240      *   - NaN is considered equal to NaN
241      *   - -0 and +0 are not considered equal
242      */
243     function identical(obj1, obj2) {
244         if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
245             return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
246         }
247     }
250     /**
251      * @name samsam.deepEqual
252      * @param Object obj1
253      * @param Object obj2
254      *
255      * Deep equal comparison. Two values are "deep equal" if:
256      *
257      *   - They are equal, according to samsam.identical
258      *   - They are both date objects representing the same time
259      *   - They are both arrays containing elements that are all deepEqual
260      *   - They are objects with the same set of properties, and each property
261      *     in ``obj1`` is deepEqual to the corresponding property in ``obj2``
262      *
263      * Supports cyclic objects.
264      */
265     function deepEqualCyclic(obj1, obj2) {
267         // used for cyclic comparison
268         // contain already visited objects
269         var objects1 = [],
270             objects2 = [],
271         // contain pathes (position in the object structure)
272         // of the already visited objects
273         // indexes same as in objects arrays
274             paths1 = [],
275             paths2 = [],
276         // contains combinations of already compared objects
277         // in the manner: { "$1['ref']$2['ref']": true }
278             compared = {};
280         /**
281          * used to check, if the value of a property is an object
282          * (cyclic logic is only needed for objects)
283          * only needed for cyclic logic
284          */
285         function isObject(value) {
287             if (typeof value === 'object' && value !== null &&
288                     !(value instanceof Boolean) &&
289                     !(value instanceof Date)    &&
290                     !(value instanceof Number)  &&
291                     !(value instanceof RegExp)  &&
292                     !(value instanceof String)) {
294                 return true;
295             }
297             return false;
298         }
300         /**
301          * returns the index of the given object in the
302          * given objects array, -1 if not contained
303          * only needed for cyclic logic
304          */
305         function getIndex(objects, obj) {
307             var i;
308             for (i = 0; i < objects.length; i++) {
309                 if (objects[i] === obj) {
310                     return i;
311                 }
312             }
314             return -1;
315         }
317         // does the recursion for the deep equal check
318         return (function deepEqual(obj1, obj2, path1, path2) {
319             var type1 = typeof obj1;
320             var type2 = typeof obj2;
322             // == null also matches undefined
323             if (obj1 === obj2 ||
324                     isNaN(obj1) || isNaN(obj2) ||
325                     obj1 == null || obj2 == null ||
326                     type1 !== "object" || type2 !== "object") {
328                 return identical(obj1, obj2);
329             }
331             // Elements are only equal if identical(expected, actual)
332             if (isElement(obj1) || isElement(obj2)) { return false; }
334             var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
335             if (isDate1 || isDate2) {
336                 if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
337                     return false;
338                 }
339             }
341             if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
342                 if (obj1.toString() !== obj2.toString()) { return false; }
343             }
345             var class1 = getClass(obj1);
346             var class2 = getClass(obj2);
347             var keys1 = keys(obj1);
348             var keys2 = keys(obj2);
350             if (isArguments(obj1) || isArguments(obj2)) {
351                 if (obj1.length !== obj2.length) { return false; }
352             } else {
353                 if (type1 !== type2 || class1 !== class2 ||
354                         keys1.length !== keys2.length) {
355                     return false;
356                 }
357             }
359             var key, i, l,
360                 // following vars are used for the cyclic logic
361                 value1, value2,
362                 isObject1, isObject2,
363                 index1, index2,
364                 newPath1, newPath2;
366             for (i = 0, l = keys1.length; i < l; i++) {
367                 key = keys1[i];
368                 if (!o.hasOwnProperty.call(obj2, key)) {
369                     return false;
370                 }
372                 // Start of the cyclic logic
374                 value1 = obj1[key];
375                 value2 = obj2[key];
377                 isObject1 = isObject(value1);
378                 isObject2 = isObject(value2);
380                 // determine, if the objects were already visited
381                 // (it's faster to check for isObject first, than to
382                 // get -1 from getIndex for non objects)
383                 index1 = isObject1 ? getIndex(objects1, value1) : -1;
384                 index2 = isObject2 ? getIndex(objects2, value2) : -1;
386                 // determine the new pathes of the objects
387                 // - for non cyclic objects the current path will be extended
388                 //   by current property name
389                 // - for cyclic objects the stored path is taken
390                 newPath1 = index1 !== -1
391                     ? paths1[index1]
392                     : path1 + '[' + JSON.stringify(key) + ']';
393                 newPath2 = index2 !== -1
394                     ? paths2[index2]
395                     : path2 + '[' + JSON.stringify(key) + ']';
397                 // stop recursion if current objects are already compared
398                 if (compared[newPath1 + newPath2]) {
399                     return true;
400                 }
402                 // remember the current objects and their pathes
403                 if (index1 === -1 && isObject1) {
404                     objects1.push(value1);
405                     paths1.push(newPath1);
406                 }
407                 if (index2 === -1 && isObject2) {
408                     objects2.push(value2);
409                     paths2.push(newPath2);
410                 }
412                 // remember that the current objects are already compared
413                 if (isObject1 && isObject2) {
414                     compared[newPath1 + newPath2] = true;
415                 }
417                 // End of cyclic logic
419                 // neither value1 nor value2 is a cycle
420                 // continue with next level
421                 if (!deepEqual(value1, value2, newPath1, newPath2)) {
422                     return false;
423                 }
424             }
426             return true;
428         }(obj1, obj2, '$1', '$2'));
429     }
431     var match;
433     function arrayContains(array, subset) {
434         if (subset.length === 0) { return true; }
435         var i, l, j, k;
436         for (i = 0, l = array.length; i < l; ++i) {
437             if (match(array[i], subset[0])) {
438                 for (j = 0, k = subset.length; j < k; ++j) {
439                     if (!match(array[i + j], subset[j])) { return false; }
440                 }
441                 return true;
442             }
443         }
444         return false;
445     }
447     /**
448      * @name samsam.match
449      * @param Object object
450      * @param Object matcher
451      *
452      * Compare arbitrary value ``object`` with matcher.
453      */
454     match = function match(object, matcher) {
455         if (matcher && typeof matcher.test === "function") {
456             return matcher.test(object);
457         }
459         if (typeof matcher === "function") {
460             return matcher(object) === true;
461         }
463         if (typeof matcher === "string") {
464             matcher = matcher.toLowerCase();
465             var notNull = typeof object === "string" || !!object;
466             return notNull &&
467                 (String(object)).toLowerCase().indexOf(matcher) >= 0;
468         }
470         if (typeof matcher === "number") {
471             return matcher === object;
472         }
474         if (typeof matcher === "boolean") {
475             return matcher === object;
476         }
478         if (getClass(object) === "Array" && getClass(matcher) === "Array") {
479             return arrayContains(object, matcher);
480         }
482         if (matcher && typeof matcher === "object") {
483             var prop;
484             for (prop in matcher) {
485                 if (!match(object[prop], matcher[prop])) {
486                     return false;
487                 }
488             }
489             return true;
490         }
492         throw new Error("Matcher was not a string, a number, a " +
493                         "function, a boolean or an object");
494     };
496     return {
497         isArguments: isArguments,
498         isElement: isElement,
499         isDate: isDate,
500         isNegZero: isNegZero,
501         identical: identical,
502         deepEqual: deepEqualCyclic,
503         match: match,
504         keys: keys
505     };
507 ((typeof define === "function" && define.amd && function (m) {
508     define("formatio", ["samsam"], m);
509 }) || (typeof module === "object" && function (m) {
510     module.exports = m(require("samsam"));
511 }) || function (m) { this.formatio = m(this.samsam); }
512 )(function (samsam) {
513     
514     var formatio = {
515         excludeConstructors: ["Object", /^.$/],
516         quoteStrings: true
517     };
519     var hasOwn = Object.prototype.hasOwnProperty;
521     var specialObjects = [];
522     if (typeof global !== "undefined") {
523         specialObjects.push({ object: global, value: "[object global]" });
524     }
525     if (typeof document !== "undefined") {
526         specialObjects.push({
527             object: document,
528             value: "[object HTMLDocument]"
529         });
530     }
531     if (typeof window !== "undefined") {
532         specialObjects.push({ object: window, value: "[object Window]" });
533     }
535     function functionName(func) {
536         if (!func) { return ""; }
537         if (func.displayName) { return func.displayName; }
538         if (func.name) { return func.name; }
539         var matches = func.toString().match(/function\s+([^\(]+)/m);
540         return (matches && matches[1]) || "";
541     }
543     function constructorName(f, object) {
544         var name = functionName(object && object.constructor);
545         var excludes = f.excludeConstructors ||
546                 formatio.excludeConstructors || [];
548         var i, l;
549         for (i = 0, l = excludes.length; i < l; ++i) {
550             if (typeof excludes[i] === "string" && excludes[i] === name) {
551                 return "";
552             } else if (excludes[i].test && excludes[i].test(name)) {
553                 return "";
554             }
555         }
557         return name;
558     }
560     function isCircular(object, objects) {
561         if (typeof object !== "object") { return false; }
562         var i, l;
563         for (i = 0, l = objects.length; i < l; ++i) {
564             if (objects[i] === object) { return true; }
565         }
566         return false;
567     }
569     function ascii(f, object, processed, indent) {
570         if (typeof object === "string") {
571             var qs = f.quoteStrings;
572             var quote = typeof qs !== "boolean" || qs;
573             return processed || quote ? '"' + object + '"' : object;
574         }
576         if (typeof object === "function" && !(object instanceof RegExp)) {
577             return ascii.func(object);
578         }
580         processed = processed || [];
582         if (isCircular(object, processed)) { return "[Circular]"; }
584         if (Object.prototype.toString.call(object) === "[object Array]") {
585             return ascii.array.call(f, object, processed);
586         }
588         if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
589         if (samsam.isElement(object)) { return ascii.element(object); }
591         if (typeof object.toString === "function" &&
592                 object.toString !== Object.prototype.toString) {
593             return object.toString();
594         }
596         var i, l;
597         for (i = 0, l = specialObjects.length; i < l; i++) {
598             if (object === specialObjects[i].object) {
599                 return specialObjects[i].value;
600             }
601         }
603         return ascii.object.call(f, object, processed, indent);
604     }
606     ascii.func = function (func) {
607         return "function " + functionName(func) + "() {}";
608     };
610     ascii.array = function (array, processed) {
611         processed = processed || [];
612         processed.push(array);
613         var i, l, pieces = [];
614         for (i = 0, l = array.length; i < l; ++i) {
615             pieces.push(ascii(this, array[i], processed));
616         }
617         return "[" + pieces.join(", ") + "]";
618     };
620     ascii.object = function (object, processed, indent) {
621         processed = processed || [];
622         processed.push(object);
623         indent = indent || 0;
624         var pieces = [], properties = samsam.keys(object).sort();
625         var length = 3;
626         var prop, str, obj, i, l;
628         for (i = 0, l = properties.length; i < l; ++i) {
629             prop = properties[i];
630             obj = object[prop];
632             if (isCircular(obj, processed)) {
633                 str = "[Circular]";
634             } else {
635                 str = ascii(this, obj, processed, indent + 2);
636             }
638             str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
639             length += str.length;
640             pieces.push(str);
641         }
643         var cons = constructorName(this, object);
644         var prefix = cons ? "[" + cons + "] " : "";
645         var is = "";
646         for (i = 0, l = indent; i < l; ++i) { is += " "; }
648         if (length + indent > 80) {
649             return prefix + "{\n  " + is + pieces.join(",\n  " + is) + "\n" +
650                 is + "}";
651         }
652         return prefix + "{ " + pieces.join(", ") + " }";
653     };
655     ascii.element = function (element) {
656         var tagName = element.tagName.toLowerCase();
657         var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
659         for (i = 0, l = attrs.length; i < l; ++i) {
660             attr = attrs.item(i);
661             attrName = attr.nodeName.toLowerCase().replace("html:", "");
662             val = attr.nodeValue;
663             if (attrName !== "contenteditable" || val !== "inherit") {
664                 if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
665             }
666         }
668         var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
669         var content = element.innerHTML;
671         if (content.length > 20) {
672             content = content.substr(0, 20) + "[...]";
673         }
675         var res = formatted + pairs.join(" ") + ">" + content +
676                 "</" + tagName + ">";
678         return res.replace(/ contentEditable="inherit"/, "");
679     };
681     function Formatio(options) {
682         for (var opt in options) {
683             this[opt] = options[opt];
684         }
685     }
687     Formatio.prototype = {
688         functionName: functionName,
690         configure: function (options) {
691             return new Formatio(options);
692         },
694         constructorName: function (object) {
695             return constructorName(this, object);
696         },
698         ascii: function (object, processed, indent) {
699             return ascii(this, object, processed, indent);
700         }
701     };
703     return Formatio.prototype;
705 /*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
706 /*global module, require, __dirname, document*/
708  * Sinon core utilities. For internal use only.
710  * @author Christian Johansen (christian@cjohansen.no)
711  * @license BSD
713  * Copyright (c) 2010-2013 Christian Johansen
714  */
716 var sinon = (function (formatio) {
717     var div = typeof document != "undefined" && document.createElement("div");
718     var hasOwn = Object.prototype.hasOwnProperty;
720     function isDOMNode(obj) {
721         var success = false;
723         try {
724             obj.appendChild(div);
725             success = div.parentNode == obj;
726         } catch (e) {
727             return false;
728         } finally {
729             try {
730                 obj.removeChild(div);
731             } catch (e) {
732                 // Remove failed, not much we can do about that
733             }
734         }
736         return success;
737     }
739     function isElement(obj) {
740         return div && obj && obj.nodeType === 1 && isDOMNode(obj);
741     }
743     function isFunction(obj) {
744         return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
745     }
747     function mirrorProperties(target, source) {
748         for (var prop in source) {
749             if (!hasOwn.call(target, prop)) {
750                 target[prop] = source[prop];
751             }
752         }
753     }
755     function isRestorable (obj) {
756         return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
757     }
759     var sinon = {
760         wrapMethod: function wrapMethod(object, property, method) {
761             if (!object) {
762                 throw new TypeError("Should wrap property of object");
763             }
765             if (typeof method != "function") {
766                 throw new TypeError("Method wrapper should be function");
767             }
769             var wrappedMethod = object[property],
770                 error;
772             if (!isFunction(wrappedMethod)) {
773                 error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
774                                     property + " as function");
775             }
777             if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
778                 error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
779             }
781             if (wrappedMethod.calledBefore) {
782                 var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
783                 error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
784             }
786             if (error) {
787                 if (wrappedMethod._stack) {
788                     error.stack += '\n--------------\n' + wrappedMethod._stack;
789                 }
790                 throw error;
791             }
793             // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
794             // when using hasOwn.call on objects from other frames.
795             var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
796             object[property] = method;
797             method.displayName = property;
798             // Set up a stack trace which can be used later to find what line of
799             // code the original method was created on.
800             method._stack = (new Error('Stack Trace for original')).stack;
802             method.restore = function () {
803                 // For prototype properties try to reset by delete first.
804                 // If this fails (ex: localStorage on mobile safari) then force a reset
805                 // via direct assignment.
806                 if (!owned) {
807                     delete object[property];
808                 }
809                 if (object[property] === method) {
810                     object[property] = wrappedMethod;
811                 }
812             };
814             method.restore.sinon = true;
815             mirrorProperties(method, wrappedMethod);
817             return method;
818         },
820         extend: function extend(target) {
821             for (var i = 1, l = arguments.length; i < l; i += 1) {
822                 for (var prop in arguments[i]) {
823                     if (arguments[i].hasOwnProperty(prop)) {
824                         target[prop] = arguments[i][prop];
825                     }
827                     // DONT ENUM bug, only care about toString
828                     if (arguments[i].hasOwnProperty("toString") &&
829                         arguments[i].toString != target.toString) {
830                         target.toString = arguments[i].toString;
831                     }
832                 }
833             }
835             return target;
836         },
838         create: function create(proto) {
839             var F = function () {};
840             F.prototype = proto;
841             return new F();
842         },
844         deepEqual: function deepEqual(a, b) {
845             if (sinon.match && sinon.match.isMatcher(a)) {
846                 return a.test(b);
847             }
848             if (typeof a != "object" || typeof b != "object") {
849                 return a === b;
850             }
852             if (isElement(a) || isElement(b)) {
853                 return a === b;
854             }
856             if (a === b) {
857                 return true;
858             }
860             if ((a === null && b !== null) || (a !== null && b === null)) {
861                 return false;
862             }
864             if (a instanceof RegExp && b instanceof RegExp) {
865               return (a.source === b.source) && (a.global === b.global) && 
866                 (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
867             }
869             var aString = Object.prototype.toString.call(a);
870             if (aString != Object.prototype.toString.call(b)) {
871                 return false;
872             }
874             if (aString == "[object Date]") {
875                 return a.valueOf() === b.valueOf();
876             }
878             var prop, aLength = 0, bLength = 0;
880             if (aString == "[object Array]" && a.length !== b.length) {
881                 return false;
882             }
884             for (prop in a) {
885                 aLength += 1;
887                 if (!deepEqual(a[prop], b[prop])) {
888                     return false;
889                 }
890             }
892             for (prop in b) {
893                 bLength += 1;
894             }
896             return aLength == bLength;
897         },
899         functionName: function functionName(func) {
900             var name = func.displayName || func.name;
902             // Use function decomposition as a last resort to get function
903             // name. Does not rely on function decomposition to work - if it
904             // doesn't debugging will be slightly less informative
905             // (i.e. toString will say 'spy' rather than 'myFunc').
906             if (!name) {
907                 var matches = func.toString().match(/function ([^\s\(]+)/);
908                 name = matches && matches[1];
909             }
911             return name;
912         },
914         functionToString: function toString() {
915             if (this.getCall && this.callCount) {
916                 var thisValue, prop, i = this.callCount;
918                 while (i--) {
919                     thisValue = this.getCall(i).thisValue;
921                     for (prop in thisValue) {
922                         if (thisValue[prop] === this) {
923                             return prop;
924                         }
925                     }
926                 }
927             }
929             return this.displayName || "sinon fake";
930         },
932         getConfig: function (custom) {
933             var config = {};
934             custom = custom || {};
935             var defaults = sinon.defaultConfig;
937             for (var prop in defaults) {
938                 if (defaults.hasOwnProperty(prop)) {
939                     config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
940                 }
941             }
943             return config;
944         },
946         format: function (val) {
947             return "" + val;
948         },
950         defaultConfig: {
951             injectIntoThis: true,
952             injectInto: null,
953             properties: ["spy", "stub", "mock", "clock", "server", "requests"],
954             useFakeTimers: true,
955             useFakeServer: true
956         },
958         timesInWords: function timesInWords(count) {
959             return count == 1 && "once" ||
960                 count == 2 && "twice" ||
961                 count == 3 && "thrice" ||
962                 (count || 0) + " times";
963         },
965         calledInOrder: function (spies) {
966             for (var i = 1, l = spies.length; i < l; i++) {
967                 if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
968                     return false;
969                 }
970             }
972             return true;
973         },
975         orderByFirstCall: function (spies) {
976             return spies.sort(function (a, b) {
977                 // uuid, won't ever be equal
978                 var aCall = a.getCall(0);
979                 var bCall = b.getCall(0);
980                 var aId = aCall && aCall.callId || -1;
981                 var bId = bCall && bCall.callId || -1;
983                 return aId < bId ? -1 : 1;
984             });
985         },
987         log: function () {},
989         logError: function (label, err) {
990             var msg = label + " threw exception: ";
991             sinon.log(msg + "[" + err.name + "] " + err.message);
992             if (err.stack) { sinon.log(err.stack); }
994             setTimeout(function () {
995                 err.message = msg + err.message;
996                 throw err;
997             }, 0);
998         },
1000         typeOf: function (value) {
1001             if (value === null) {
1002                 return "null";
1003             }
1004             else if (value === undefined) {
1005                 return "undefined";
1006             }
1007             var string = Object.prototype.toString.call(value);
1008             return string.substring(8, string.length - 1).toLowerCase();
1009         },
1011         createStubInstance: function (constructor) {
1012             if (typeof constructor !== "function") {
1013                 throw new TypeError("The constructor should be a function.");
1014             }
1015             return sinon.stub(sinon.create(constructor.prototype));
1016         },
1018         restore: function (object) {
1019             if (object !== null && typeof object === "object") {
1020                 for (var prop in object) {
1021                     if (isRestorable(object[prop])) {
1022                         object[prop].restore();
1023                     }
1024                 }
1025             }
1026             else if (isRestorable(object)) {
1027                 object.restore();
1028             }
1029         }
1030     };
1032     var isNode = typeof module !== "undefined" && module.exports;
1033     var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
1035     if (isAMD) {
1036         define(function(){
1037             return sinon;
1038         });
1039     } else if (isNode) {
1040         try {
1041             formatio = require("formatio");
1042         } catch (e) {}
1043         module.exports = sinon;
1044         module.exports.spy = require("./sinon/spy");
1045         module.exports.spyCall = require("./sinon/call");
1046         module.exports.behavior = require("./sinon/behavior");
1047         module.exports.stub = require("./sinon/stub");
1048         module.exports.mock = require("./sinon/mock");
1049         module.exports.collection = require("./sinon/collection");
1050         module.exports.assert = require("./sinon/assert");
1051         module.exports.sandbox = require("./sinon/sandbox");
1052         module.exports.test = require("./sinon/test");
1053         module.exports.testCase = require("./sinon/test_case");
1054         module.exports.assert = require("./sinon/assert");
1055         module.exports.match = require("./sinon/match");
1056     }
1058     if (formatio) {
1059         var formatter = formatio.configure({ quoteStrings: false });
1060         sinon.format = function () {
1061             return formatter.ascii.apply(formatter, arguments);
1062         };
1063     } else if (isNode) {
1064         try {
1065             var util = require("util");
1066             sinon.format = function (value) {
1067                 return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
1068             };
1069         } catch (e) {
1070             /* Node, but no util module - would be very old, but better safe than
1071              sorry */
1072         }
1073     }
1075     return sinon;
1076 }(typeof formatio == "object" && formatio));
1078 /* @depend ../sinon.js */
1079 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
1080 /*global module, require, sinon*/
1082  * Match functions
1084  * @author Maximilian Antoni (mail@maxantoni.de)
1085  * @license BSD
1087  * Copyright (c) 2012 Maximilian Antoni
1088  */
1090 (function (sinon) {
1091     var commonJSModule = typeof module !== 'undefined' && module.exports;
1093     if (!sinon && commonJSModule) {
1094         sinon = require("../sinon");
1095     }
1097     if (!sinon) {
1098         return;
1099     }
1101     function assertType(value, type, name) {
1102         var actual = sinon.typeOf(value);
1103         if (actual !== type) {
1104             throw new TypeError("Expected type of " + name + " to be " +
1105                 type + ", but was " + actual);
1106         }
1107     }
1109     var matcher = {
1110         toString: function () {
1111             return this.message;
1112         }
1113     };
1115     function isMatcher(object) {
1116         return matcher.isPrototypeOf(object);
1117     }
1119     function matchObject(expectation, actual) {
1120         if (actual === null || actual === undefined) {
1121             return false;
1122         }
1123         for (var key in expectation) {
1124             if (expectation.hasOwnProperty(key)) {
1125                 var exp = expectation[key];
1126                 var act = actual[key];
1127                 if (match.isMatcher(exp)) {
1128                     if (!exp.test(act)) {
1129                         return false;
1130                     }
1131                 } else if (sinon.typeOf(exp) === "object") {
1132                     if (!matchObject(exp, act)) {
1133                         return false;
1134                     }
1135                 } else if (!sinon.deepEqual(exp, act)) {
1136                     return false;
1137                 }
1138             }
1139         }
1140         return true;
1141     }
1143     matcher.or = function (m2) {
1144         if (!arguments.length) {
1145             throw new TypeError("Matcher expected");
1146         } else if (!isMatcher(m2)) {
1147             m2 = match(m2);
1148         }
1149         var m1 = this;
1150         var or = sinon.create(matcher);
1151         or.test = function (actual) {
1152             return m1.test(actual) || m2.test(actual);
1153         };
1154         or.message = m1.message + ".or(" + m2.message + ")";
1155         return or;
1156     };
1158     matcher.and = function (m2) {
1159         if (!arguments.length) {
1160             throw new TypeError("Matcher expected");
1161         } else if (!isMatcher(m2)) {
1162             m2 = match(m2);
1163         }
1164         var m1 = this;
1165         var and = sinon.create(matcher);
1166         and.test = function (actual) {
1167             return m1.test(actual) && m2.test(actual);
1168         };
1169         and.message = m1.message + ".and(" + m2.message + ")";
1170         return and;
1171     };
1173     var match = function (expectation, message) {
1174         var m = sinon.create(matcher);
1175         var type = sinon.typeOf(expectation);
1176         switch (type) {
1177         case "object":
1178             if (typeof expectation.test === "function") {
1179                 m.test = function (actual) {
1180                     return expectation.test(actual) === true;
1181                 };
1182                 m.message = "match(" + sinon.functionName(expectation.test) + ")";
1183                 return m;
1184             }
1185             var str = [];
1186             for (var key in expectation) {
1187                 if (expectation.hasOwnProperty(key)) {
1188                     str.push(key + ": " + expectation[key]);
1189                 }
1190             }
1191             m.test = function (actual) {
1192                 return matchObject(expectation, actual);
1193             };
1194             m.message = "match(" + str.join(", ") + ")";
1195             break;
1196         case "number":
1197             m.test = function (actual) {
1198                 return expectation == actual;
1199             };
1200             break;
1201         case "string":
1202             m.test = function (actual) {
1203                 if (typeof actual !== "string") {
1204                     return false;
1205                 }
1206                 return actual.indexOf(expectation) !== -1;
1207             };
1208             m.message = "match(\"" + expectation + "\")";
1209             break;
1210         case "regexp":
1211             m.test = function (actual) {
1212                 if (typeof actual !== "string") {
1213                     return false;
1214                 }
1215                 return expectation.test(actual);
1216             };
1217             break;
1218         case "function":
1219             m.test = expectation;
1220             if (message) {
1221                 m.message = message;
1222             } else {
1223                 m.message = "match(" + sinon.functionName(expectation) + ")";
1224             }
1225             break;
1226         default:
1227             m.test = function (actual) {
1228               return sinon.deepEqual(expectation, actual);
1229             };
1230         }
1231         if (!m.message) {
1232             m.message = "match(" + expectation + ")";
1233         }
1234         return m;
1235     };
1237     match.isMatcher = isMatcher;
1239     match.any = match(function () {
1240         return true;
1241     }, "any");
1243     match.defined = match(function (actual) {
1244         return actual !== null && actual !== undefined;
1245     }, "defined");
1247     match.truthy = match(function (actual) {
1248         return !!actual;
1249     }, "truthy");
1251     match.falsy = match(function (actual) {
1252         return !actual;
1253     }, "falsy");
1255     match.same = function (expectation) {
1256         return match(function (actual) {
1257             return expectation === actual;
1258         }, "same(" + expectation + ")");
1259     };
1261     match.typeOf = function (type) {
1262         assertType(type, "string", "type");
1263         return match(function (actual) {
1264             return sinon.typeOf(actual) === type;
1265         }, "typeOf(\"" + type + "\")");
1266     };
1268     match.instanceOf = function (type) {
1269         assertType(type, "function", "type");
1270         return match(function (actual) {
1271             return actual instanceof type;
1272         }, "instanceOf(" + sinon.functionName(type) + ")");
1273     };
1275     function createPropertyMatcher(propertyTest, messagePrefix) {
1276         return function (property, value) {
1277             assertType(property, "string", "property");
1278             var onlyProperty = arguments.length === 1;
1279             var message = messagePrefix + "(\"" + property + "\"";
1280             if (!onlyProperty) {
1281                 message += ", " + value;
1282             }
1283             message += ")";
1284             return match(function (actual) {
1285                 if (actual === undefined || actual === null ||
1286                         !propertyTest(actual, property)) {
1287                     return false;
1288                 }
1289                 return onlyProperty || sinon.deepEqual(value, actual[property]);
1290             }, message);
1291         };
1292     }
1294     match.has = createPropertyMatcher(function (actual, property) {
1295         if (typeof actual === "object") {
1296             return property in actual;
1297         }
1298         return actual[property] !== undefined;
1299     }, "has");
1301     match.hasOwn = createPropertyMatcher(function (actual, property) {
1302         return actual.hasOwnProperty(property);
1303     }, "hasOwn");
1305     match.bool = match.typeOf("boolean");
1306     match.number = match.typeOf("number");
1307     match.string = match.typeOf("string");
1308     match.object = match.typeOf("object");
1309     match.func = match.typeOf("function");
1310     match.array = match.typeOf("array");
1311     match.regexp = match.typeOf("regexp");
1312     match.date = match.typeOf("date");
1314     if (commonJSModule) {
1315         module.exports = match;
1316     } else {
1317         sinon.match = match;
1318     }
1319 }(typeof sinon == "object" && sinon || null));
1322   * @depend ../sinon.js
1323   * @depend match.js
1324   */
1325 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
1326 /*global module, require, sinon*/
1328   * Spy calls
1329   *
1330   * @author Christian Johansen (christian@cjohansen.no)
1331   * @author Maximilian Antoni (mail@maxantoni.de)
1332   * @license BSD
1333   *
1334   * Copyright (c) 2010-2013 Christian Johansen
1335   * Copyright (c) 2013 Maximilian Antoni
1336   */
1338 (function (sinon) {
1339     var commonJSModule = typeof module !== 'undefined' && module.exports;
1340     if (!sinon && commonJSModule) {
1341         sinon = require("../sinon");
1342     }
1344     if (!sinon) {
1345         return;
1346     }
1348     function throwYieldError(proxy, text, args) {
1349         var msg = sinon.functionName(proxy) + text;
1350         if (args.length) {
1351             msg += " Received [" + slice.call(args).join(", ") + "]";
1352         }
1353         throw new Error(msg);
1354     }
1356     var slice = Array.prototype.slice;
1358     var callProto = {
1359         calledOn: function calledOn(thisValue) {
1360             if (sinon.match && sinon.match.isMatcher(thisValue)) {
1361                 return thisValue.test(this.thisValue);
1362             }
1363             return this.thisValue === thisValue;
1364         },
1366         calledWith: function calledWith() {
1367             for (var i = 0, l = arguments.length; i < l; i += 1) {
1368                 if (!sinon.deepEqual(arguments[i], this.args[i])) {
1369                     return false;
1370                 }
1371             }
1373             return true;
1374         },
1376         calledWithMatch: function calledWithMatch() {
1377             for (var i = 0, l = arguments.length; i < l; i += 1) {
1378                 var actual = this.args[i];
1379                 var expectation = arguments[i];
1380                 if (!sinon.match || !sinon.match(expectation).test(actual)) {
1381                     return false;
1382                 }
1383             }
1384             return true;
1385         },
1387         calledWithExactly: function calledWithExactly() {
1388             return arguments.length == this.args.length &&
1389                 this.calledWith.apply(this, arguments);
1390         },
1392         notCalledWith: function notCalledWith() {
1393             return !this.calledWith.apply(this, arguments);
1394         },
1396         notCalledWithMatch: function notCalledWithMatch() {
1397             return !this.calledWithMatch.apply(this, arguments);
1398         },
1400         returned: function returned(value) {
1401             return sinon.deepEqual(value, this.returnValue);
1402         },
1404         threw: function threw(error) {
1405             if (typeof error === "undefined" || !this.exception) {
1406                 return !!this.exception;
1407             }
1409             return this.exception === error || this.exception.name === error;
1410         },
1412         calledWithNew: function calledWithNew() {
1413             return this.proxy.prototype && this.thisValue instanceof this.proxy;
1414         },
1416         calledBefore: function (other) {
1417             return this.callId < other.callId;
1418         },
1420         calledAfter: function (other) {
1421             return this.callId > other.callId;
1422         },
1424         callArg: function (pos) {
1425             this.args[pos]();
1426         },
1428         callArgOn: function (pos, thisValue) {
1429             this.args[pos].apply(thisValue);
1430         },
1432         callArgWith: function (pos) {
1433             this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
1434         },
1436         callArgOnWith: function (pos, thisValue) {
1437             var args = slice.call(arguments, 2);
1438             this.args[pos].apply(thisValue, args);
1439         },
1441         "yield": function () {
1442             this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
1443         },
1445         yieldOn: function (thisValue) {
1446             var args = this.args;
1447             for (var i = 0, l = args.length; i < l; ++i) {
1448                 if (typeof args[i] === "function") {
1449                     args[i].apply(thisValue, slice.call(arguments, 1));
1450                     return;
1451                 }
1452             }
1453             throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
1454         },
1456         yieldTo: function (prop) {
1457             this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
1458         },
1460         yieldToOn: function (prop, thisValue) {
1461             var args = this.args;
1462             for (var i = 0, l = args.length; i < l; ++i) {
1463                 if (args[i] && typeof args[i][prop] === "function") {
1464                     args[i][prop].apply(thisValue, slice.call(arguments, 2));
1465                     return;
1466                 }
1467             }
1468             throwYieldError(this.proxy, " cannot yield to '" + prop +
1469                 "' since no callback was passed.", args);
1470         },
1472         toString: function () {
1473             var callStr = this.proxy.toString() + "(";
1474             var args = [];
1476             for (var i = 0, l = this.args.length; i < l; ++i) {
1477                 args.push(sinon.format(this.args[i]));
1478             }
1480             callStr = callStr + args.join(", ") + ")";
1482             if (typeof this.returnValue != "undefined") {
1483                 callStr += " => " + sinon.format(this.returnValue);
1484             }
1486             if (this.exception) {
1487                 callStr += " !" + this.exception.name;
1489                 if (this.exception.message) {
1490                     callStr += "(" + this.exception.message + ")";
1491                 }
1492             }
1494             return callStr;
1495         }
1496     };
1498     callProto.invokeCallback = callProto.yield;
1500     function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
1501         if (typeof id !== "number") {
1502             throw new TypeError("Call id is not a number");
1503         }
1504         var proxyCall = sinon.create(callProto);
1505         proxyCall.proxy = spy;
1506         proxyCall.thisValue = thisValue;
1507         proxyCall.args = args;
1508         proxyCall.returnValue = returnValue;
1509         proxyCall.exception = exception;
1510         proxyCall.callId = id;
1512         return proxyCall;
1513     }
1514     createSpyCall.toString = callProto.toString; // used by mocks
1516     if (commonJSModule) {
1517         module.exports = createSpyCall;
1518     } else {
1519         sinon.spyCall = createSpyCall;
1520     }
1521 }(typeof sinon == "object" && sinon || null));
1525   * @depend ../sinon.js
1526   * @depend call.js
1527   */
1528 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
1529 /*global module, require, sinon*/
1531   * Spy functions
1532   *
1533   * @author Christian Johansen (christian@cjohansen.no)
1534   * @license BSD
1535   *
1536   * Copyright (c) 2010-2013 Christian Johansen
1537   */
1539 (function (sinon) {
1540     var commonJSModule = typeof module !== 'undefined' && module.exports;
1541     var push = Array.prototype.push;
1542     var slice = Array.prototype.slice;
1543     var callId = 0;
1545     if (!sinon && commonJSModule) {
1546         sinon = require("../sinon");
1547     }
1549     if (!sinon) {
1550         return;
1551     }
1553     function spy(object, property) {
1554         if (!property && typeof object == "function") {
1555             return spy.create(object);
1556         }
1558         if (!object && !property) {
1559             return spy.create(function () { });
1560         }
1562         var method = object[property];
1563         return sinon.wrapMethod(object, property, spy.create(method));
1564     }
1566     function matchingFake(fakes, args, strict) {
1567         if (!fakes) {
1568             return;
1569         }
1571         for (var i = 0, l = fakes.length; i < l; i++) {
1572             if (fakes[i].matches(args, strict)) {
1573                 return fakes[i];
1574             }
1575         }
1576     }
1578     function incrementCallCount() {
1579         this.called = true;
1580         this.callCount += 1;
1581         this.notCalled = false;
1582         this.calledOnce = this.callCount == 1;
1583         this.calledTwice = this.callCount == 2;
1584         this.calledThrice = this.callCount == 3;
1585     }
1587     function createCallProperties() {
1588         this.firstCall = this.getCall(0);
1589         this.secondCall = this.getCall(1);
1590         this.thirdCall = this.getCall(2);
1591         this.lastCall = this.getCall(this.callCount - 1);
1592     }
1594     var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
1595     function createProxy(func) {
1596         // Retain the function length:
1597         var p;
1598         if (func.length) {
1599             eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
1600                 ") { return p.invoke(func, this, slice.call(arguments)); });");
1601         }
1602         else {
1603             p = function proxy() {
1604                 return p.invoke(func, this, slice.call(arguments));
1605             };
1606         }
1607         return p;
1608     }
1610     var uuid = 0;
1612     // Public API
1613     var spyApi = {
1614         reset: function () {
1615             this.called = false;
1616             this.notCalled = true;
1617             this.calledOnce = false;
1618             this.calledTwice = false;
1619             this.calledThrice = false;
1620             this.callCount = 0;
1621             this.firstCall = null;
1622             this.secondCall = null;
1623             this.thirdCall = null;
1624             this.lastCall = null;
1625             this.args = [];
1626             this.returnValues = [];
1627             this.thisValues = [];
1628             this.exceptions = [];
1629             this.callIds = [];
1630             if (this.fakes) {
1631                 for (var i = 0; i < this.fakes.length; i++) {
1632                     this.fakes[i].reset();
1633                 }
1634             }
1635         },
1637         create: function create(func) {
1638             var name;
1640             if (typeof func != "function") {
1641                 func = function () { };
1642             } else {
1643                 name = sinon.functionName(func);
1644             }
1646             var proxy = createProxy(func);
1648             sinon.extend(proxy, spy);
1649             delete proxy.create;
1650             sinon.extend(proxy, func);
1652             proxy.reset();
1653             proxy.prototype = func.prototype;
1654             proxy.displayName = name || "spy";
1655             proxy.toString = sinon.functionToString;
1656             proxy._create = sinon.spy.create;
1657             proxy.id = "spy#" + uuid++;
1659             return proxy;
1660         },
1662         invoke: function invoke(func, thisValue, args) {
1663             var matching = matchingFake(this.fakes, args);
1664             var exception, returnValue;
1666             incrementCallCount.call(this);
1667             push.call(this.thisValues, thisValue);
1668             push.call(this.args, args);
1669             push.call(this.callIds, callId++);
1671             try {
1672                 if (matching) {
1673                     returnValue = matching.invoke(func, thisValue, args);
1674                 } else {
1675                     returnValue = (this.func || func).apply(thisValue, args);
1676                 }
1678                 var thisCall = this.getCall(this.callCount - 1);
1679                 if (thisCall.calledWithNew() && typeof returnValue !== 'object') {
1680                     returnValue = thisValue;
1681                 }
1682             } catch (e) {
1683                 exception = e;
1684             }
1686             push.call(this.exceptions, exception);
1687             push.call(this.returnValues, returnValue);
1689             createCallProperties.call(this);
1691             if (exception !== undefined) {
1692                 throw exception;
1693             }
1695             return returnValue;
1696         },
1698         getCall: function getCall(i) {
1699             if (i < 0 || i >= this.callCount) {
1700                 return null;
1701             }
1703             return sinon.spyCall(this, this.thisValues[i], this.args[i],
1704                                     this.returnValues[i], this.exceptions[i],
1705                                     this.callIds[i]);
1706         },
1708         getCalls: function () {
1709             var calls = [];
1710             var i;
1712             for (i = 0; i < this.callCount; i++) {
1713                 calls.push(this.getCall(i));
1714             }
1716             return calls;
1717         },
1719         calledBefore: function calledBefore(spyFn) {
1720             if (!this.called) {
1721                 return false;
1722             }
1724             if (!spyFn.called) {
1725                 return true;
1726             }
1728             return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
1729         },
1731         calledAfter: function calledAfter(spyFn) {
1732             if (!this.called || !spyFn.called) {
1733                 return false;
1734             }
1736             return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
1737         },
1739         withArgs: function () {
1740             var args = slice.call(arguments);
1742             if (this.fakes) {
1743                 var match = matchingFake(this.fakes, args, true);
1745                 if (match) {
1746                     return match;
1747                 }
1748             } else {
1749                 this.fakes = [];
1750             }
1752             var original = this;
1753             var fake = this._create();
1754             fake.matchingAguments = args;
1755             fake.parent = this;
1756             push.call(this.fakes, fake);
1758             fake.withArgs = function () {
1759                 return original.withArgs.apply(original, arguments);
1760             };
1762             for (var i = 0; i < this.args.length; i++) {
1763                 if (fake.matches(this.args[i])) {
1764                     incrementCallCount.call(fake);
1765                     push.call(fake.thisValues, this.thisValues[i]);
1766                     push.call(fake.args, this.args[i]);
1767                     push.call(fake.returnValues, this.returnValues[i]);
1768                     push.call(fake.exceptions, this.exceptions[i]);
1769                     push.call(fake.callIds, this.callIds[i]);
1770                 }
1771             }
1772             createCallProperties.call(fake);
1774             return fake;
1775         },
1777         matches: function (args, strict) {
1778             var margs = this.matchingAguments;
1780             if (margs.length <= args.length &&
1781                 sinon.deepEqual(margs, args.slice(0, margs.length))) {
1782                 return !strict || margs.length == args.length;
1783             }
1784         },
1786         printf: function (format) {
1787             var spy = this;
1788             var args = slice.call(arguments, 1);
1789             var formatter;
1791             return (format || "").replace(/%(.)/g, function (match, specifyer) {
1792                 formatter = spyApi.formatters[specifyer];
1794                 if (typeof formatter == "function") {
1795                     return formatter.call(null, spy, args);
1796                 } else if (!isNaN(parseInt(specifyer, 10))) {
1797                     return sinon.format(args[specifyer - 1]);
1798                 }
1800                 return "%" + specifyer;
1801             });
1802         }
1803     };
1805     function delegateToCalls(method, matchAny, actual, notCalled) {
1806         spyApi[method] = function () {
1807             if (!this.called) {
1808                 if (notCalled) {
1809                     return notCalled.apply(this, arguments);
1810                 }
1811                 return false;
1812             }
1814             var currentCall;
1815             var matches = 0;
1817             for (var i = 0, l = this.callCount; i < l; i += 1) {
1818                 currentCall = this.getCall(i);
1820                 if (currentCall[actual || method].apply(currentCall, arguments)) {
1821                     matches += 1;
1823                     if (matchAny) {
1824                         return true;
1825                     }
1826                 }
1827             }
1829             return matches === this.callCount;
1830         };
1831     }
1833     delegateToCalls("calledOn", true);
1834     delegateToCalls("alwaysCalledOn", false, "calledOn");
1835     delegateToCalls("calledWith", true);
1836     delegateToCalls("calledWithMatch", true);
1837     delegateToCalls("alwaysCalledWith", false, "calledWith");
1838     delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
1839     delegateToCalls("calledWithExactly", true);
1840     delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
1841     delegateToCalls("neverCalledWith", false, "notCalledWith",
1842         function () { return true; });
1843     delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
1844         function () { return true; });
1845     delegateToCalls("threw", true);
1846     delegateToCalls("alwaysThrew", false, "threw");
1847     delegateToCalls("returned", true);
1848     delegateToCalls("alwaysReturned", false, "returned");
1849     delegateToCalls("calledWithNew", true);
1850     delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
1851     delegateToCalls("callArg", false, "callArgWith", function () {
1852         throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
1853     });
1854     spyApi.callArgWith = spyApi.callArg;
1855     delegateToCalls("callArgOn", false, "callArgOnWith", function () {
1856         throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
1857     });
1858     spyApi.callArgOnWith = spyApi.callArgOn;
1859     delegateToCalls("yield", false, "yield", function () {
1860         throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
1861     });
1862     // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
1863     spyApi.invokeCallback = spyApi.yield;
1864     delegateToCalls("yieldOn", false, "yieldOn", function () {
1865         throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
1866     });
1867     delegateToCalls("yieldTo", false, "yieldTo", function (property) {
1868         throw new Error(this.toString() + " cannot yield to '" + property +
1869             "' since it was not yet invoked.");
1870     });
1871     delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
1872         throw new Error(this.toString() + " cannot yield to '" + property +
1873             "' since it was not yet invoked.");
1874     });
1876     spyApi.formatters = {
1877         "c": function (spy) {
1878             return sinon.timesInWords(spy.callCount);
1879         },
1881         "n": function (spy) {
1882             return spy.toString();
1883         },
1885         "C": function (spy) {
1886             var calls = [];
1888             for (var i = 0, l = spy.callCount; i < l; ++i) {
1889                 var stringifiedCall = "    " + spy.getCall(i).toString();
1890                 if (/\n/.test(calls[i - 1])) {
1891                     stringifiedCall = "\n" + stringifiedCall;
1892                 }
1893                 push.call(calls, stringifiedCall);
1894             }
1896             return calls.length > 0 ? "\n" + calls.join("\n") : "";
1897         },
1899         "t": function (spy) {
1900             var objects = [];
1902             for (var i = 0, l = spy.callCount; i < l; ++i) {
1903                 push.call(objects, sinon.format(spy.thisValues[i]));
1904             }
1906             return objects.join(", ");
1907         },
1909         "*": function (spy, args) {
1910             var formatted = [];
1912             for (var i = 0, l = args.length; i < l; ++i) {
1913                 push.call(formatted, sinon.format(args[i]));
1914             }
1916             return formatted.join(", ");
1917         }
1918     };
1920     sinon.extend(spy, spyApi);
1922     spy.spyCall = sinon.spyCall;
1924     if (commonJSModule) {
1925         module.exports = spy;
1926     } else {
1927         sinon.spy = spy;
1928     }
1929 }(typeof sinon == "object" && sinon || null));
1932  * @depend ../sinon.js
1933  */
1934 /*jslint eqeqeq: false, onevar: false*/
1935 /*global module, require, sinon, process, setImmediate, setTimeout*/
1937  * Stub behavior
1939  * @author Christian Johansen (christian@cjohansen.no)
1940  * @author Tim Fischbach (mail@timfischbach.de)
1941  * @license BSD
1943  * Copyright (c) 2010-2013 Christian Johansen
1944  */
1946 (function (sinon) {
1947     var commonJSModule = typeof module !== 'undefined' && module.exports;
1949     if (!sinon && commonJSModule) {
1950         sinon = require("../sinon");
1951     }
1953     if (!sinon) {
1954         return;
1955     }
1957     var slice = Array.prototype.slice;
1958     var join = Array.prototype.join;
1959     var proto;
1961     var nextTick = (function () {
1962         if (typeof process === "object" && typeof process.nextTick === "function") {
1963             return process.nextTick;
1964         } else if (typeof setImmediate === "function") {
1965             return setImmediate;
1966         } else {
1967             return function (callback) {
1968                 setTimeout(callback, 0);
1969             };
1970         }
1971     })();
1973     function throwsException(error, message) {
1974         if (typeof error == "string") {
1975             this.exception = new Error(message || "");
1976             this.exception.name = error;
1977         } else if (!error) {
1978             this.exception = new Error("Error");
1979         } else {
1980             this.exception = error;
1981         }
1983         return this;
1984     }
1986     function getCallback(behavior, args) {
1987         var callArgAt = behavior.callArgAt;
1989         if (callArgAt < 0) {
1990             var callArgProp = behavior.callArgProp;
1992             for (var i = 0, l = args.length; i < l; ++i) {
1993                 if (!callArgProp && typeof args[i] == "function") {
1994                     return args[i];
1995                 }
1997                 if (callArgProp && args[i] &&
1998                     typeof args[i][callArgProp] == "function") {
1999                     return args[i][callArgProp];
2000                 }
2001             }
2003             return null;
2004         }
2006         return args[callArgAt];
2007     }
2009     function getCallbackError(behavior, func, args) {
2010         if (behavior.callArgAt < 0) {
2011             var msg;
2013             if (behavior.callArgProp) {
2014                 msg = sinon.functionName(behavior.stub) +
2015                     " expected to yield to '" + behavior.callArgProp +
2016                     "', but no object with such a property was passed.";
2017             } else {
2018                 msg = sinon.functionName(behavior.stub) +
2019                     " expected to yield, but no callback was passed.";
2020             }
2022             if (args.length > 0) {
2023                 msg += " Received [" + join.call(args, ", ") + "]";
2024             }
2026             return msg;
2027         }
2029         return "argument at index " + behavior.callArgAt + " is not a function: " + func;
2030     }
2032     function callCallback(behavior, args) {
2033         if (typeof behavior.callArgAt == "number") {
2034             var func = getCallback(behavior, args);
2036             if (typeof func != "function") {
2037                 throw new TypeError(getCallbackError(behavior, func, args));
2038             }
2040             if (behavior.callbackAsync) {
2041                 nextTick(function() {
2042                     func.apply(behavior.callbackContext, behavior.callbackArguments);
2043                 });
2044             } else {
2045                 func.apply(behavior.callbackContext, behavior.callbackArguments);
2046             }
2047         }
2048     }
2050     proto = {
2051         create: function(stub) {
2052             var behavior = sinon.extend({}, sinon.behavior);
2053             delete behavior.create;
2054             behavior.stub = stub;
2056             return behavior;
2057         },
2059         isPresent: function() {
2060             return (typeof this.callArgAt == 'number' ||
2061                     this.exception ||
2062                     typeof this.returnArgAt == 'number' ||
2063                     this.returnThis ||
2064                     this.returnValueDefined);
2065         },
2067         invoke: function(context, args) {
2068             callCallback(this, args);
2070             if (this.exception) {
2071                 throw this.exception;
2072             } else if (typeof this.returnArgAt == 'number') {
2073                 return args[this.returnArgAt];
2074             } else if (this.returnThis) {
2075                 return context;
2076             }
2078             return this.returnValue;
2079         },
2081         onCall: function(index) {
2082             return this.stub.onCall(index);
2083         },
2085         onFirstCall: function() {
2086             return this.stub.onFirstCall();
2087         },
2089         onSecondCall: function() {
2090             return this.stub.onSecondCall();
2091         },
2093         onThirdCall: function() {
2094             return this.stub.onThirdCall();
2095         },
2097         withArgs: function(/* arguments */) {
2098             throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' +
2099                             'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.');
2100         },
2102         callsArg: function callsArg(pos) {
2103             if (typeof pos != "number") {
2104                 throw new TypeError("argument index is not number");
2105             }
2107             this.callArgAt = pos;
2108             this.callbackArguments = [];
2109             this.callbackContext = undefined;
2110             this.callArgProp = undefined;
2111             this.callbackAsync = false;
2113             return this;
2114         },
2116         callsArgOn: function callsArgOn(pos, context) {
2117             if (typeof pos != "number") {
2118                 throw new TypeError("argument index is not number");
2119             }
2120             if (typeof context != "object") {
2121                 throw new TypeError("argument context is not an object");
2122             }
2124             this.callArgAt = pos;
2125             this.callbackArguments = [];
2126             this.callbackContext = context;
2127             this.callArgProp = undefined;
2128             this.callbackAsync = false;
2130             return this;
2131         },
2133         callsArgWith: function callsArgWith(pos) {
2134             if (typeof pos != "number") {
2135                 throw new TypeError("argument index is not number");
2136             }
2138             this.callArgAt = pos;
2139             this.callbackArguments = slice.call(arguments, 1);
2140             this.callbackContext = undefined;
2141             this.callArgProp = undefined;
2142             this.callbackAsync = false;
2144             return this;
2145         },
2147         callsArgOnWith: function callsArgWith(pos, context) {
2148             if (typeof pos != "number") {
2149                 throw new TypeError("argument index is not number");
2150             }
2151             if (typeof context != "object") {
2152                 throw new TypeError("argument context is not an object");
2153             }
2155             this.callArgAt = pos;
2156             this.callbackArguments = slice.call(arguments, 2);
2157             this.callbackContext = context;
2158             this.callArgProp = undefined;
2159             this.callbackAsync = false;
2161             return this;
2162         },
2164         yields: function () {
2165             this.callArgAt = -1;
2166             this.callbackArguments = slice.call(arguments, 0);
2167             this.callbackContext = undefined;
2168             this.callArgProp = undefined;
2169             this.callbackAsync = false;
2171             return this;
2172         },
2174         yieldsOn: function (context) {
2175             if (typeof context != "object") {
2176                 throw new TypeError("argument context is not an object");
2177             }
2179             this.callArgAt = -1;
2180             this.callbackArguments = slice.call(arguments, 1);
2181             this.callbackContext = context;
2182             this.callArgProp = undefined;
2183             this.callbackAsync = false;
2185             return this;
2186         },
2188         yieldsTo: function (prop) {
2189             this.callArgAt = -1;
2190             this.callbackArguments = slice.call(arguments, 1);
2191             this.callbackContext = undefined;
2192             this.callArgProp = prop;
2193             this.callbackAsync = false;
2195             return this;
2196         },
2198         yieldsToOn: function (prop, context) {
2199             if (typeof context != "object") {
2200                 throw new TypeError("argument context is not an object");
2201             }
2203             this.callArgAt = -1;
2204             this.callbackArguments = slice.call(arguments, 2);
2205             this.callbackContext = context;
2206             this.callArgProp = prop;
2207             this.callbackAsync = false;
2209             return this;
2210         },
2213         "throws": throwsException,
2214         throwsException: throwsException,
2216         returns: function returns(value) {
2217             this.returnValue = value;
2218             this.returnValueDefined = true;
2220             return this;
2221         },
2223         returnsArg: function returnsArg(pos) {
2224             if (typeof pos != "number") {
2225                 throw new TypeError("argument index is not number");
2226             }
2228             this.returnArgAt = pos;
2230             return this;
2231         },
2233         returnsThis: function returnsThis() {
2234             this.returnThis = true;
2236             return this;
2237         }
2238     };
2240     // create asynchronous versions of callsArg* and yields* methods
2241     for (var method in proto) {
2242         // need to avoid creating anotherasync versions of the newly added async methods
2243         if (proto.hasOwnProperty(method) &&
2244             method.match(/^(callsArg|yields)/) &&
2245             !method.match(/Async/)) {
2246             proto[method + 'Async'] = (function (syncFnName) {
2247                 return function () {
2248                     var result = this[syncFnName].apply(this, arguments);
2249                     this.callbackAsync = true;
2250                     return result;
2251                 };
2252             })(method);
2253         }
2254     }
2256     if (commonJSModule) {
2257         module.exports = proto;
2258     } else {
2259         sinon.behavior = proto;
2260     }
2261 }(typeof sinon == "object" && sinon || null));
2263  * @depend ../sinon.js
2264  * @depend spy.js
2265  * @depend behavior.js
2266  */
2267 /*jslint eqeqeq: false, onevar: false*/
2268 /*global module, require, sinon*/
2270  * Stub functions
2272  * @author Christian Johansen (christian@cjohansen.no)
2273  * @license BSD
2275  * Copyright (c) 2010-2013 Christian Johansen
2276  */
2278 (function (sinon) {
2279     var commonJSModule = typeof module !== 'undefined' && module.exports;
2281     if (!sinon && commonJSModule) {
2282         sinon = require("../sinon");
2283     }
2285     if (!sinon) {
2286         return;
2287     }
2289     function stub(object, property, func) {
2290         if (!!func && typeof func != "function") {
2291             throw new TypeError("Custom stub should be function");
2292         }
2294         var wrapper;
2296         if (func) {
2297             wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
2298         } else {
2299             wrapper = stub.create();
2300         }
2302         if (!object && typeof property === "undefined") {
2303             return sinon.stub.create();
2304         }
2306         if (typeof property === "undefined" && typeof object == "object") {
2307             for (var prop in object) {
2308                 if (typeof object[prop] === "function") {
2309                     stub(object, prop);
2310                 }
2311             }
2313             return object;
2314         }
2316         return sinon.wrapMethod(object, property, wrapper);
2317     }
2319     function getDefaultBehavior(stub) {
2320         return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
2321     }
2323     function getParentBehaviour(stub) {
2324         return (stub.parent && getCurrentBehavior(stub.parent));
2325     }
2327     function getCurrentBehavior(stub) {
2328         var behavior = stub.behaviors[stub.callCount - 1];
2329         return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
2330     }
2332     var uuid = 0;
2334     sinon.extend(stub, (function () {
2335         var proto = {
2336             create: function create() {
2337                 var functionStub = function () {
2338                     return getCurrentBehavior(functionStub).invoke(this, arguments);
2339                 };
2341                 functionStub.id = "stub#" + uuid++;
2342                 var orig = functionStub;
2343                 functionStub = sinon.spy.create(functionStub);
2344                 functionStub.func = orig;
2346                 sinon.extend(functionStub, stub);
2347                 functionStub._create = sinon.stub.create;
2348                 functionStub.displayName = "stub";
2349                 functionStub.toString = sinon.functionToString;
2351                 functionStub.defaultBehavior = null;
2352                 functionStub.behaviors = [];
2354                 return functionStub;
2355             },
2357             resetBehavior: function () {
2358                 var i;
2360                 this.defaultBehavior = null;
2361                 this.behaviors = [];
2363                 delete this.returnValue;
2364                 delete this.returnArgAt;
2365                 this.returnThis = false;
2367                 if (this.fakes) {
2368                     for (i = 0; i < this.fakes.length; i++) {
2369                         this.fakes[i].resetBehavior();
2370                     }
2371                 }
2372             },
2374             onCall: function(index) {
2375                 if (!this.behaviors[index]) {
2376                     this.behaviors[index] = sinon.behavior.create(this);
2377                 }
2379                 return this.behaviors[index];
2380             },
2382             onFirstCall: function() {
2383                 return this.onCall(0);
2384             },
2386             onSecondCall: function() {
2387                 return this.onCall(1);
2388             },
2390             onThirdCall: function() {
2391                 return this.onCall(2);
2392             }
2393         };
2395         for (var method in sinon.behavior) {
2396             if (sinon.behavior.hasOwnProperty(method) &&
2397                 !proto.hasOwnProperty(method) &&
2398                 method != 'create' &&
2399                 method != 'withArgs' &&
2400                 method != 'invoke') {
2401                 proto[method] = (function(behaviorMethod) {
2402                     return function() {
2403                         this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
2404                         this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
2405                         return this;
2406                     };
2407                 }(method));
2408             }
2409         }
2411         return proto;
2412     }()));
2414     if (commonJSModule) {
2415         module.exports = stub;
2416     } else {
2417         sinon.stub = stub;
2418     }
2419 }(typeof sinon == "object" && sinon || null));
2422  * @depend ../sinon.js
2423  * @depend stub.js
2424  */
2425 /*jslint eqeqeq: false, onevar: false, nomen: false*/
2426 /*global module, require, sinon*/
2428  * Mock functions.
2430  * @author Christian Johansen (christian@cjohansen.no)
2431  * @license BSD
2433  * Copyright (c) 2010-2013 Christian Johansen
2434  */
2436 (function (sinon) {
2437     var commonJSModule = typeof module !== 'undefined' && module.exports;
2438     var push = [].push;
2439     var match;
2441     if (!sinon && commonJSModule) {
2442         sinon = require("../sinon");
2443     }
2445     if (!sinon) {
2446         return;
2447     }
2449     match = sinon.match;
2451     if (!match && commonJSModule) {
2452         match = require("./match");
2453     }
2455     function mock(object) {
2456         if (!object) {
2457             return sinon.expectation.create("Anonymous mock");
2458         }
2460         return mock.create(object);
2461     }
2463     sinon.mock = mock;
2465     sinon.extend(mock, (function () {
2466         function each(collection, callback) {
2467             if (!collection) {
2468                 return;
2469             }
2471             for (var i = 0, l = collection.length; i < l; i += 1) {
2472                 callback(collection[i]);
2473             }
2474         }
2476         return {
2477             create: function create(object) {
2478                 if (!object) {
2479                     throw new TypeError("object is null");
2480                 }
2482                 var mockObject = sinon.extend({}, mock);
2483                 mockObject.object = object;
2484                 delete mockObject.create;
2486                 return mockObject;
2487             },
2489             expects: function expects(method) {
2490                 if (!method) {
2491                     throw new TypeError("method is falsy");
2492                 }
2494                 if (!this.expectations) {
2495                     this.expectations = {};
2496                     this.proxies = [];
2497                 }
2499                 if (!this.expectations[method]) {
2500                     this.expectations[method] = [];
2501                     var mockObject = this;
2503                     sinon.wrapMethod(this.object, method, function () {
2504                         return mockObject.invokeMethod(method, this, arguments);
2505                     });
2507                     push.call(this.proxies, method);
2508                 }
2510                 var expectation = sinon.expectation.create(method);
2511                 push.call(this.expectations[method], expectation);
2513                 return expectation;
2514             },
2516             restore: function restore() {
2517                 var object = this.object;
2519                 each(this.proxies, function (proxy) {
2520                     if (typeof object[proxy].restore == "function") {
2521                         object[proxy].restore();
2522                     }
2523                 });
2524             },
2526             verify: function verify() {
2527                 var expectations = this.expectations || {};
2528                 var messages = [], met = [];
2530                 each(this.proxies, function (proxy) {
2531                     each(expectations[proxy], function (expectation) {
2532                         if (!expectation.met()) {
2533                             push.call(messages, expectation.toString());
2534                         } else {
2535                             push.call(met, expectation.toString());
2536                         }
2537                     });
2538                 });
2540                 this.restore();
2542                 if (messages.length > 0) {
2543                     sinon.expectation.fail(messages.concat(met).join("\n"));
2544                 } else {
2545                     sinon.expectation.pass(messages.concat(met).join("\n"));
2546                 }
2548                 return true;
2549             },
2551             invokeMethod: function invokeMethod(method, thisValue, args) {
2552                 var expectations = this.expectations && this.expectations[method];
2553                 var length = expectations && expectations.length || 0, i;
2555                 for (i = 0; i < length; i += 1) {
2556                     if (!expectations[i].met() &&
2557                         expectations[i].allowsCall(thisValue, args)) {
2558                         return expectations[i].apply(thisValue, args);
2559                     }
2560                 }
2562                 var messages = [], available, exhausted = 0;
2564                 for (i = 0; i < length; i += 1) {
2565                     if (expectations[i].allowsCall(thisValue, args)) {
2566                         available = available || expectations[i];
2567                     } else {
2568                         exhausted += 1;
2569                     }
2570                     push.call(messages, "    " + expectations[i].toString());
2571                 }
2573                 if (exhausted === 0) {
2574                     return available.apply(thisValue, args);
2575                 }
2577                 messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
2578                     proxy: method,
2579                     args: args
2580                 }));
2582                 sinon.expectation.fail(messages.join("\n"));
2583             }
2584         };
2585     }()));
2587     var times = sinon.timesInWords;
2589     sinon.expectation = (function () {
2590         var slice = Array.prototype.slice;
2591         var _invoke = sinon.spy.invoke;
2593         function callCountInWords(callCount) {
2594             if (callCount == 0) {
2595                 return "never called";
2596             } else {
2597                 return "called " + times(callCount);
2598             }
2599         }
2601         function expectedCallCountInWords(expectation) {
2602             var min = expectation.minCalls;
2603             var max = expectation.maxCalls;
2605             if (typeof min == "number" && typeof max == "number") {
2606                 var str = times(min);
2608                 if (min != max) {
2609                     str = "at least " + str + " and at most " + times(max);
2610                 }
2612                 return str;
2613             }
2615             if (typeof min == "number") {
2616                 return "at least " + times(min);
2617             }
2619             return "at most " + times(max);
2620         }
2622         function receivedMinCalls(expectation) {
2623             var hasMinLimit = typeof expectation.minCalls == "number";
2624             return !hasMinLimit || expectation.callCount >= expectation.minCalls;
2625         }
2627         function receivedMaxCalls(expectation) {
2628             if (typeof expectation.maxCalls != "number") {
2629                 return false;
2630             }
2632             return expectation.callCount == expectation.maxCalls;
2633         }
2635         function verifyMatcher(possibleMatcher, arg){
2636             if (match && match.isMatcher(possibleMatcher)) {
2637                 return possibleMatcher.test(arg);
2638             } else {
2639                 return true;
2640             }
2641         }
2643         return {
2644             minCalls: 1,
2645             maxCalls: 1,
2647             create: function create(methodName) {
2648                 var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
2649                 delete expectation.create;
2650                 expectation.method = methodName;
2652                 return expectation;
2653             },
2655             invoke: function invoke(func, thisValue, args) {
2656                 this.verifyCallAllowed(thisValue, args);
2658                 return _invoke.apply(this, arguments);
2659             },
2661             atLeast: function atLeast(num) {
2662                 if (typeof num != "number") {
2663                     throw new TypeError("'" + num + "' is not number");
2664                 }
2666                 if (!this.limitsSet) {
2667                     this.maxCalls = null;
2668                     this.limitsSet = true;
2669                 }
2671                 this.minCalls = num;
2673                 return this;
2674             },
2676             atMost: function atMost(num) {
2677                 if (typeof num != "number") {
2678                     throw new TypeError("'" + num + "' is not number");
2679                 }
2681                 if (!this.limitsSet) {
2682                     this.minCalls = null;
2683                     this.limitsSet = true;
2684                 }
2686                 this.maxCalls = num;
2688                 return this;
2689             },
2691             never: function never() {
2692                 return this.exactly(0);
2693             },
2695             once: function once() {
2696                 return this.exactly(1);
2697             },
2699             twice: function twice() {
2700                 return this.exactly(2);
2701             },
2703             thrice: function thrice() {
2704                 return this.exactly(3);
2705             },
2707             exactly: function exactly(num) {
2708                 if (typeof num != "number") {
2709                     throw new TypeError("'" + num + "' is not a number");
2710                 }
2712                 this.atLeast(num);
2713                 return this.atMost(num);
2714             },
2716             met: function met() {
2717                 return !this.failed && receivedMinCalls(this);
2718             },
2720             verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
2721                 if (receivedMaxCalls(this)) {
2722                     this.failed = true;
2723                     sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
2724                 }
2726                 if ("expectedThis" in this && this.expectedThis !== thisValue) {
2727                     sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
2728                         this.expectedThis);
2729                 }
2731                 if (!("expectedArguments" in this)) {
2732                     return;
2733                 }
2735                 if (!args) {
2736                     sinon.expectation.fail(this.method + " received no arguments, expected " +
2737                         sinon.format(this.expectedArguments));
2738                 }
2740                 if (args.length < this.expectedArguments.length) {
2741                     sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
2742                         "), expected " + sinon.format(this.expectedArguments));
2743                 }
2745                 if (this.expectsExactArgCount &&
2746                     args.length != this.expectedArguments.length) {
2747                     sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
2748                         "), expected " + sinon.format(this.expectedArguments));
2749                 }
2751                 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2753                     if (!verifyMatcher(this.expectedArguments[i],args[i])) {
2754                         sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
2755                             ", didn't match " + this.expectedArguments.toString());
2756                     }
2758                     if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
2759                         sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
2760                             ", expected " + sinon.format(this.expectedArguments));
2761                     }
2762                 }
2763             },
2765             allowsCall: function allowsCall(thisValue, args) {
2766                 if (this.met() && receivedMaxCalls(this)) {
2767                     return false;
2768                 }
2770                 if ("expectedThis" in this && this.expectedThis !== thisValue) {
2771                     return false;
2772                 }
2774                 if (!("expectedArguments" in this)) {
2775                     return true;
2776                 }
2778                 args = args || [];
2780                 if (args.length < this.expectedArguments.length) {
2781                     return false;
2782                 }
2784                 if (this.expectsExactArgCount &&
2785                     args.length != this.expectedArguments.length) {
2786                     return false;
2787                 }
2789                 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2790                     if (!verifyMatcher(this.expectedArguments[i],args[i])) {
2791                         return false;
2792                     }
2794                     if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
2795                         return false;
2796                     }
2797                 }
2799                 return true;
2800             },
2802             withArgs: function withArgs() {
2803                 this.expectedArguments = slice.call(arguments);
2804                 return this;
2805             },
2807             withExactArgs: function withExactArgs() {
2808                 this.withArgs.apply(this, arguments);
2809                 this.expectsExactArgCount = true;
2810                 return this;
2811             },
2813             on: function on(thisValue) {
2814                 this.expectedThis = thisValue;
2815                 return this;
2816             },
2818             toString: function () {
2819                 var args = (this.expectedArguments || []).slice();
2821                 if (!this.expectsExactArgCount) {
2822                     push.call(args, "[...]");
2823                 }
2825                 var callStr = sinon.spyCall.toString.call({
2826                     proxy: this.method || "anonymous mock expectation",
2827                     args: args
2828                 });
2830                 var message = callStr.replace(", [...", "[, ...") + " " +
2831                     expectedCallCountInWords(this);
2833                 if (this.met()) {
2834                     return "Expectation met: " + message;
2835                 }
2837                 return "Expected " + message + " (" +
2838                     callCountInWords(this.callCount) + ")";
2839             },
2841             verify: function verify() {
2842                 if (!this.met()) {
2843                     sinon.expectation.fail(this.toString());
2844                 } else {
2845                     sinon.expectation.pass(this.toString());
2846                 }
2848                 return true;
2849             },
2851             pass: function(message) {
2852               sinon.assert.pass(message);
2853             },
2854             fail: function (message) {
2855                 var exception = new Error(message);
2856                 exception.name = "ExpectationError";
2858                 throw exception;
2859             }
2860         };
2861     }());
2863     if (commonJSModule) {
2864         module.exports = mock;
2865     } else {
2866         sinon.mock = mock;
2867     }
2868 }(typeof sinon == "object" && sinon || null));
2871  * @depend ../sinon.js
2872  * @depend stub.js
2873  * @depend mock.js
2874  */
2875 /*jslint eqeqeq: false, onevar: false, forin: true*/
2876 /*global module, require, sinon*/
2878  * Collections of stubs, spies and mocks.
2880  * @author Christian Johansen (christian@cjohansen.no)
2881  * @license BSD
2883  * Copyright (c) 2010-2013 Christian Johansen
2884  */
2886 (function (sinon) {
2887     var commonJSModule = typeof module !== 'undefined' && module.exports;
2888     var push = [].push;
2889     var hasOwnProperty = Object.prototype.hasOwnProperty;
2891     if (!sinon && commonJSModule) {
2892         sinon = require("../sinon");
2893     }
2895     if (!sinon) {
2896         return;
2897     }
2899     function getFakes(fakeCollection) {
2900         if (!fakeCollection.fakes) {
2901             fakeCollection.fakes = [];
2902         }
2904         return fakeCollection.fakes;
2905     }
2907     function each(fakeCollection, method) {
2908         var fakes = getFakes(fakeCollection);
2910         for (var i = 0, l = fakes.length; i < l; i += 1) {
2911             if (typeof fakes[i][method] == "function") {
2912                 fakes[i][method]();
2913             }
2914         }
2915     }
2917     function compact(fakeCollection) {
2918         var fakes = getFakes(fakeCollection);
2919         var i = 0;
2920         while (i < fakes.length) {
2921           fakes.splice(i, 1);
2922         }
2923     }
2925     var collection = {
2926         verify: function resolve() {
2927             each(this, "verify");
2928         },
2930         restore: function restore() {
2931             each(this, "restore");
2932             compact(this);
2933         },
2935         verifyAndRestore: function verifyAndRestore() {
2936             var exception;
2938             try {
2939                 this.verify();
2940             } catch (e) {
2941                 exception = e;
2942             }
2944             this.restore();
2946             if (exception) {
2947                 throw exception;
2948             }
2949         },
2951         add: function add(fake) {
2952             push.call(getFakes(this), fake);
2953             return fake;
2954         },
2956         spy: function spy() {
2957             return this.add(sinon.spy.apply(sinon, arguments));
2958         },
2960         stub: function stub(object, property, value) {
2961             if (property) {
2962                 var original = object[property];
2964                 if (typeof original != "function") {
2965                     if (!hasOwnProperty.call(object, property)) {
2966                         throw new TypeError("Cannot stub non-existent own property " + property);
2967                     }
2969                     object[property] = value;
2971                     return this.add({
2972                         restore: function () {
2973                             object[property] = original;
2974                         }
2975                     });
2976                 }
2977             }
2978             if (!property && !!object && typeof object == "object") {
2979                 var stubbedObj = sinon.stub.apply(sinon, arguments);
2981                 for (var prop in stubbedObj) {
2982                     if (typeof stubbedObj[prop] === "function") {
2983                         this.add(stubbedObj[prop]);
2984                     }
2985                 }
2987                 return stubbedObj;
2988             }
2990             return this.add(sinon.stub.apply(sinon, arguments));
2991         },
2993         mock: function mock() {
2994             return this.add(sinon.mock.apply(sinon, arguments));
2995         },
2997         inject: function inject(obj) {
2998             var col = this;
3000             obj.spy = function () {
3001                 return col.spy.apply(col, arguments);
3002             };
3004             obj.stub = function () {
3005                 return col.stub.apply(col, arguments);
3006             };
3008             obj.mock = function () {
3009                 return col.mock.apply(col, arguments);
3010             };
3012             return obj;
3013         }
3014     };
3016     if (commonJSModule) {
3017         module.exports = collection;
3018     } else {
3019         sinon.collection = collection;
3020     }
3021 }(typeof sinon == "object" && sinon || null));
3023 /*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
3024 /*global module, require, window*/
3026  * Fake timer API
3027  * setTimeout
3028  * setInterval
3029  * clearTimeout
3030  * clearInterval
3031  * tick
3032  * reset
3033  * Date
3035  * Inspired by jsUnitMockTimeOut from JsUnit
3037  * @author Christian Johansen (christian@cjohansen.no)
3038  * @license BSD
3040  * Copyright (c) 2010-2013 Christian Johansen
3041  */
3043 if (typeof sinon == "undefined") {
3044     var sinon = {};
3047 (function (global) {
3048     var id = 1;
3050     function addTimer(args, recurring) {
3051         if (args.length === 0) {
3052             throw new Error("Function requires at least 1 parameter");
3053         }
3055         if (typeof args[0] === "undefined") {
3056             throw new Error("Callback must be provided to timer calls");
3057         }
3059         var toId = id++;
3060         var delay = args[1] || 0;
3062         if (!this.timeouts) {
3063             this.timeouts = {};
3064         }
3066         this.timeouts[toId] = {
3067             id: toId,
3068             func: args[0],
3069             callAt: this.now + delay,
3070             invokeArgs: Array.prototype.slice.call(args, 2)
3071         };
3073         if (recurring === true) {
3074             this.timeouts[toId].interval = delay;
3075         }
3077         return toId;
3078     }
3080     function parseTime(str) {
3081         if (!str) {
3082             return 0;
3083         }
3085         var strings = str.split(":");
3086         var l = strings.length, i = l;
3087         var ms = 0, parsed;
3089         if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
3090             throw new Error("tick only understands numbers and 'h:m:s'");
3091         }
3093         while (i--) {
3094             parsed = parseInt(strings[i], 10);
3096             if (parsed >= 60) {
3097                 throw new Error("Invalid time " + str);
3098             }
3100             ms += parsed * Math.pow(60, (l - i - 1));
3101         }
3103         return ms * 1000;
3104     }
3106     function createObject(object) {
3107         var newObject;
3109         if (Object.create) {
3110             newObject = Object.create(object);
3111         } else {
3112             var F = function () {};
3113             F.prototype = object;
3114             newObject = new F();
3115         }
3117         newObject.Date.clock = newObject;
3118         return newObject;
3119     }
3121     sinon.clock = {
3122         now: 0,
3124         create: function create(now) {
3125             var clock = createObject(this);
3127             if (typeof now == "number") {
3128                 clock.now = now;
3129             }
3131             if (!!now && typeof now == "object") {
3132                 throw new TypeError("now should be milliseconds since UNIX epoch");
3133             }
3135             return clock;
3136         },
3138         setTimeout: function setTimeout(callback, timeout) {
3139             return addTimer.call(this, arguments, false);
3140         },
3142         clearTimeout: function clearTimeout(timerId) {
3143             if (!this.timeouts) {
3144                 this.timeouts = [];
3145             }
3147             if (timerId in this.timeouts) {
3148                 delete this.timeouts[timerId];
3149             }
3150         },
3152         setInterval: function setInterval(callback, timeout) {
3153             return addTimer.call(this, arguments, true);
3154         },
3156         clearInterval: function clearInterval(timerId) {
3157             this.clearTimeout(timerId);
3158         },
3160         setImmediate: function setImmediate(callback) {
3161             var passThruArgs = Array.prototype.slice.call(arguments, 1);
3163             return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
3164         },
3166         clearImmediate: function clearImmediate(timerId) {
3167             this.clearTimeout(timerId);
3168         },
3170         tick: function tick(ms) {
3171             ms = typeof ms == "number" ? ms : parseTime(ms);
3172             var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
3173             var timer = this.firstTimerInRange(tickFrom, tickTo);
3175             var firstException;
3176             while (timer && tickFrom <= tickTo) {
3177                 if (this.timeouts[timer.id]) {
3178                     tickFrom = this.now = timer.callAt;
3179                     try {
3180                       this.callTimer(timer);
3181                     } catch (e) {
3182                       firstException = firstException || e;
3183                     }
3184                 }
3186                 timer = this.firstTimerInRange(previous, tickTo);
3187                 previous = tickFrom;
3188             }
3190             this.now = tickTo;
3192             if (firstException) {
3193               throw firstException;
3194             }
3196             return this.now;
3197         },
3199         firstTimerInRange: function (from, to) {
3200             var timer, smallest = null, originalTimer;
3202             for (var id in this.timeouts) {
3203                 if (this.timeouts.hasOwnProperty(id)) {
3204                     if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
3205                         continue;
3206                     }
3208                     if (smallest === null || this.timeouts[id].callAt < smallest) {
3209                         originalTimer = this.timeouts[id];
3210                         smallest = this.timeouts[id].callAt;
3212                         timer = {
3213                             func: this.timeouts[id].func,
3214                             callAt: this.timeouts[id].callAt,
3215                             interval: this.timeouts[id].interval,
3216                             id: this.timeouts[id].id,
3217                             invokeArgs: this.timeouts[id].invokeArgs
3218                         };
3219                     }
3220                 }
3221             }
3223             return timer || null;
3224         },
3226         callTimer: function (timer) {
3227             if (typeof timer.interval == "number") {
3228                 this.timeouts[timer.id].callAt += timer.interval;
3229             } else {
3230                 delete this.timeouts[timer.id];
3231             }
3233             try {
3234                 if (typeof timer.func == "function") {
3235                     timer.func.apply(null, timer.invokeArgs);
3236                 } else {
3237                     eval(timer.func);
3238                 }
3239             } catch (e) {
3240               var exception = e;
3241             }
3243             if (!this.timeouts[timer.id]) {
3244                 if (exception) {
3245                   throw exception;
3246                 }
3247                 return;
3248             }
3250             if (exception) {
3251               throw exception;
3252             }
3253         },
3255         reset: function reset() {
3256             this.timeouts = {};
3257         },
3259         Date: (function () {
3260             var NativeDate = Date;
3262             function ClockDate(year, month, date, hour, minute, second, ms) {
3263                 // Defensive and verbose to avoid potential harm in passing
3264                 // explicit undefined when user does not pass argument
3265                 switch (arguments.length) {
3266                 case 0:
3267                     return new NativeDate(ClockDate.clock.now);
3268                 case 1:
3269                     return new NativeDate(year);
3270                 case 2:
3271                     return new NativeDate(year, month);
3272                 case 3:
3273                     return new NativeDate(year, month, date);
3274                 case 4:
3275                     return new NativeDate(year, month, date, hour);
3276                 case 5:
3277                     return new NativeDate(year, month, date, hour, minute);
3278                 case 6:
3279                     return new NativeDate(year, month, date, hour, minute, second);
3280                 default:
3281                     return new NativeDate(year, month, date, hour, minute, second, ms);
3282                 }
3283             }
3285             return mirrorDateProperties(ClockDate, NativeDate);
3286         }())
3287     };
3289     function mirrorDateProperties(target, source) {
3290         if (source.now) {
3291             target.now = function now() {
3292                 return target.clock.now;
3293             };
3294         } else {
3295             delete target.now;
3296         }
3298         if (source.toSource) {
3299             target.toSource = function toSource() {
3300                 return source.toSource();
3301             };
3302         } else {
3303             delete target.toSource;
3304         }
3306         target.toString = function toString() {
3307             return source.toString();
3308         };
3310         target.prototype = source.prototype;
3311         target.parse = source.parse;
3312         target.UTC = source.UTC;
3313         target.prototype.toUTCString = source.prototype.toUTCString;
3315         for (var prop in source) {
3316             if (source.hasOwnProperty(prop)) {
3317                 target[prop] = source[prop];
3318             }
3319         }
3321         return target;
3322     }
3324     var methods = ["Date", "setTimeout", "setInterval",
3325                    "clearTimeout", "clearInterval"];
3327     if (typeof global.setImmediate !== "undefined") {
3328         methods.push("setImmediate");
3329     }
3331     if (typeof global.clearImmediate !== "undefined") {
3332         methods.push("clearImmediate");
3333     }
3335     function restore() {
3336         var method;
3338         for (var i = 0, l = this.methods.length; i < l; i++) {
3339             method = this.methods[i];
3341             if (global[method].hadOwnProperty) {
3342                 global[method] = this["_" + method];
3343             } else {
3344                 try {
3345                     delete global[method];
3346                 } catch (e) {}
3347             }
3348         }
3350         // Prevent multiple executions which will completely remove these props
3351         this.methods = [];
3352     }
3354     function stubGlobal(method, clock) {
3355         clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
3356         clock["_" + method] = global[method];
3358         if (method == "Date") {
3359             var date = mirrorDateProperties(clock[method], global[method]);
3360             global[method] = date;
3361         } else {
3362             global[method] = function () {
3363                 return clock[method].apply(clock, arguments);
3364             };
3366             for (var prop in clock[method]) {
3367                 if (clock[method].hasOwnProperty(prop)) {
3368                     global[method][prop] = clock[method][prop];
3369                 }
3370             }
3371         }
3373         global[method].clock = clock;
3374     }
3376     sinon.useFakeTimers = function useFakeTimers(now) {
3377         var clock = sinon.clock.create(now);
3378         clock.restore = restore;
3379         clock.methods = Array.prototype.slice.call(arguments,
3380                                                    typeof now == "number" ? 1 : 0);
3382         if (clock.methods.length === 0) {
3383             clock.methods = methods;
3384         }
3386         for (var i = 0, l = clock.methods.length; i < l; i++) {
3387             stubGlobal(clock.methods[i], clock);
3388         }
3390         return clock;
3391     };
3392 }(typeof global != "undefined" && typeof global !== "function" ? global : this));
3394 sinon.timers = {
3395     setTimeout: setTimeout,
3396     clearTimeout: clearTimeout,
3397     setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
3398     clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
3399     setInterval: setInterval,
3400     clearInterval: clearInterval,
3401     Date: Date
3404 if (typeof module !== 'undefined' && module.exports) {
3405     module.exports = sinon;
3408 /*jslint eqeqeq: false, onevar: false*/
3409 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
3411  * Minimal Event interface implementation
3413  * Original implementation by Sven Fuchs: https://gist.github.com/995028
3414  * Modifications and tests by Christian Johansen.
3416  * @author Sven Fuchs (svenfuchs@artweb-design.de)
3417  * @author Christian Johansen (christian@cjohansen.no)
3418  * @license BSD
3420  * Copyright (c) 2011 Sven Fuchs, Christian Johansen
3421  */
3423 if (typeof sinon == "undefined") {
3424     this.sinon = {};
3427 (function () {
3428     var push = [].push;
3430     sinon.Event = function Event(type, bubbles, cancelable, target) {
3431         this.initEvent(type, bubbles, cancelable, target);
3432     };
3434     sinon.Event.prototype = {
3435         initEvent: function(type, bubbles, cancelable, target) {
3436             this.type = type;
3437             this.bubbles = bubbles;
3438             this.cancelable = cancelable;
3439             this.target = target;
3440         },
3442         stopPropagation: function () {},
3444         preventDefault: function () {
3445             this.defaultPrevented = true;
3446         }
3447     };
3449     sinon.EventTarget = {
3450         addEventListener: function addEventListener(event, listener) {
3451             this.eventListeners = this.eventListeners || {};
3452             this.eventListeners[event] = this.eventListeners[event] || [];
3453             push.call(this.eventListeners[event], listener);
3454         },
3456         removeEventListener: function removeEventListener(event, listener) {
3457             var listeners = this.eventListeners && this.eventListeners[event] || [];
3459             for (var i = 0, l = listeners.length; i < l; ++i) {
3460                 if (listeners[i] == listener) {
3461                     return listeners.splice(i, 1);
3462                 }
3463             }
3464         },
3466         dispatchEvent: function dispatchEvent(event) {
3467             var type = event.type;
3468             var listeners = this.eventListeners && this.eventListeners[type] || [];
3470             for (var i = 0; i < listeners.length; i++) {
3471                 if (typeof listeners[i] == "function") {
3472                     listeners[i].call(this, event);
3473                 } else {
3474                     listeners[i].handleEvent(event);
3475                 }
3476             }
3478             return !!event.defaultPrevented;
3479         }
3480     };
3481 }());
3484  * @depend ../../sinon.js
3485  * @depend event.js
3486  */
3487 /*jslint eqeqeq: false, onevar: false*/
3488 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
3490  * Fake XMLHttpRequest object
3492  * @author Christian Johansen (christian@cjohansen.no)
3493  * @license BSD
3495  * Copyright (c) 2010-2013 Christian Johansen
3496  */
3498 // wrapper for global
3499 (function(global) {
3500     if (typeof sinon === "undefined") {
3501         global.sinon = {};
3502     }
3504     var supportsProgress = typeof ProgressEvent !== "undefined";
3505     var supportsCustomEvent = typeof CustomEvent !== "undefined";
3506     sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
3507     var xhr = sinon.xhr;
3508     xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
3509     xhr.GlobalActiveXObject = global.ActiveXObject;
3510     xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
3511     xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
3512     xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
3513                                      ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
3514     xhr.supportsCORS = 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
3516     /*jsl:ignore*/
3517     var unsafeHeaders = {
3518         "Accept-Charset": true,
3519         "Accept-Encoding": true,
3520         "Connection": true,
3521         "Content-Length": true,
3522         "Cookie": true,
3523         "Cookie2": true,
3524         "Content-Transfer-Encoding": true,
3525         "Date": true,
3526         "Expect": true,
3527         "Host": true,
3528         "Keep-Alive": true,
3529         "Referer": true,
3530         "TE": true,
3531         "Trailer": true,
3532         "Transfer-Encoding": true,
3533         "Upgrade": true,
3534         "User-Agent": true,
3535         "Via": true
3536     };
3537     /*jsl:end*/
3539     function FakeXMLHttpRequest() {
3540         this.readyState = FakeXMLHttpRequest.UNSENT;
3541         this.requestHeaders = {};
3542         this.requestBody = null;
3543         this.status = 0;
3544         this.statusText = "";
3545         this.upload = new UploadProgress();
3546         if (sinon.xhr.supportsCORS) {
3547             this.withCredentials = false;
3548         }
3551         var xhr = this;
3552         var events = ["loadstart", "load", "abort", "loadend"];
3554         function addEventListener(eventName) {
3555             xhr.addEventListener(eventName, function (event) {
3556                 var listener = xhr["on" + eventName];
3558                 if (listener && typeof listener == "function") {
3559                     listener(event);
3560                 }
3561             });
3562         }
3564         for (var i = events.length - 1; i >= 0; i--) {
3565             addEventListener(events[i]);
3566         }
3568         if (typeof FakeXMLHttpRequest.onCreate == "function") {
3569             FakeXMLHttpRequest.onCreate(this);
3570         }
3571     }
3573     // An upload object is created for each
3574     // FakeXMLHttpRequest and allows upload
3575     // events to be simulated using uploadProgress
3576     // and uploadError.
3577     function UploadProgress() {
3578         this.eventListeners = {
3579             "progress": [],
3580             "load": [],
3581             "abort": [],
3582             "error": []
3583         }
3584     }
3586     UploadProgress.prototype.addEventListener = function(event, listener) {
3587         this.eventListeners[event].push(listener);
3588     };
3590     UploadProgress.prototype.removeEventListener = function(event, listener) {
3591         var listeners = this.eventListeners[event] || [];
3593         for (var i = 0, l = listeners.length; i < l; ++i) {
3594             if (listeners[i] == listener) {
3595                 return listeners.splice(i, 1);
3596             }
3597         }
3598     };
3600     UploadProgress.prototype.dispatchEvent = function(event) {
3601         var listeners = this.eventListeners[event.type] || [];
3603         for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
3604             listener(event);
3605         }
3606     };
3608     function verifyState(xhr) {
3609         if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
3610             throw new Error("INVALID_STATE_ERR");
3611         }
3613         if (xhr.sendFlag) {
3614             throw new Error("INVALID_STATE_ERR");
3615         }
3616     }
3618     // filtering to enable a white-list version of Sinon FakeXhr,
3619     // where whitelisted requests are passed through to real XHR
3620     function each(collection, callback) {
3621         if (!collection) return;
3622         for (var i = 0, l = collection.length; i < l; i += 1) {
3623             callback(collection[i]);
3624         }
3625     }
3626     function some(collection, callback) {
3627         for (var index = 0; index < collection.length; index++) {
3628             if(callback(collection[index]) === true) return true;
3629         }
3630         return false;
3631     }
3632     // largest arity in XHR is 5 - XHR#open
3633     var apply = function(obj,method,args) {
3634         switch(args.length) {
3635         case 0: return obj[method]();
3636         case 1: return obj[method](args[0]);
3637         case 2: return obj[method](args[0],args[1]);
3638         case 3: return obj[method](args[0],args[1],args[2]);
3639         case 4: return obj[method](args[0],args[1],args[2],args[3]);
3640         case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
3641         }
3642     };
3644     FakeXMLHttpRequest.filters = [];
3645     FakeXMLHttpRequest.addFilter = function(fn) {
3646         this.filters.push(fn)
3647     };
3648     var IE6Re = /MSIE 6/;
3649     FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
3650         var xhr = new sinon.xhr.workingXHR();
3651         each(["open","setRequestHeader","send","abort","getResponseHeader",
3652               "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
3653              function(method) {
3654                  fakeXhr[method] = function() {
3655                    return apply(xhr,method,arguments);
3656                  };
3657              });
3659         var copyAttrs = function(args) {
3660             each(args, function(attr) {
3661               try {
3662                 fakeXhr[attr] = xhr[attr]
3663               } catch(e) {
3664                 if(!IE6Re.test(navigator.userAgent)) throw e;
3665               }
3666             });
3667         };
3669         var stateChange = function() {
3670             fakeXhr.readyState = xhr.readyState;
3671             if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
3672                 copyAttrs(["status","statusText"]);
3673             }
3674             if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
3675                 copyAttrs(["responseText"]);
3676             }
3677             if(xhr.readyState === FakeXMLHttpRequest.DONE) {
3678                 copyAttrs(["responseXML"]);
3679             }
3680             if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
3681         };
3682         if(xhr.addEventListener) {
3683           for(var event in fakeXhr.eventListeners) {
3684               if(fakeXhr.eventListeners.hasOwnProperty(event)) {
3685                   each(fakeXhr.eventListeners[event],function(handler) {
3686                       xhr.addEventListener(event, handler);
3687                   });
3688               }
3689           }
3690           xhr.addEventListener("readystatechange",stateChange);
3691         } else {
3692           xhr.onreadystatechange = stateChange;
3693         }
3694         apply(xhr,"open",xhrArgs);
3695     };
3696     FakeXMLHttpRequest.useFilters = false;
3698     function verifyRequestSent(xhr) {
3699         if (xhr.readyState == FakeXMLHttpRequest.DONE) {
3700             throw new Error("Request done");
3701         }
3702     }
3704     function verifyHeadersReceived(xhr) {
3705         if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
3706             throw new Error("No headers received");
3707         }
3708     }
3710     function verifyResponseBodyType(body) {
3711         if (typeof body != "string") {
3712             var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
3713                                  body + ", which is not a string.");
3714             error.name = "InvalidBodyException";
3715             throw error;
3716         }
3717     }
3719     sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
3720         async: true,
3722         open: function open(method, url, async, username, password) {
3723             this.method = method;
3724             this.url = url;
3725             this.async = typeof async == "boolean" ? async : true;
3726             this.username = username;
3727             this.password = password;
3728             this.responseText = null;
3729             this.responseXML = null;
3730             this.requestHeaders = {};
3731             this.sendFlag = false;
3732             if(sinon.FakeXMLHttpRequest.useFilters === true) {
3733                 var xhrArgs = arguments;
3734                 var defake = some(FakeXMLHttpRequest.filters,function(filter) {
3735                     return filter.apply(this,xhrArgs)
3736                 });
3737                 if (defake) {
3738                   return sinon.FakeXMLHttpRequest.defake(this,arguments);
3739                 }
3740             }
3741             this.readyStateChange(FakeXMLHttpRequest.OPENED);
3742         },
3744         readyStateChange: function readyStateChange(state) {
3745             this.readyState = state;
3747             if (typeof this.onreadystatechange == "function") {
3748                 try {
3749                     this.onreadystatechange();
3750                 } catch (e) {
3751                     sinon.logError("Fake XHR onreadystatechange handler", e);
3752                 }
3753             }
3755             this.dispatchEvent(new sinon.Event("readystatechange"));
3757             switch (this.readyState) {
3758                 case FakeXMLHttpRequest.DONE:
3759                     this.dispatchEvent(new sinon.Event("load", false, false, this));
3760                     this.dispatchEvent(new sinon.Event("loadend", false, false, this));
3761                     this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
3762                     if (supportsProgress) {
3763                         this.upload.dispatchEvent(new sinon.Event("progress", {loaded: 100, total: 100}));
3764                     }
3765                     break;
3766             }
3767         },
3769         setRequestHeader: function setRequestHeader(header, value) {
3770             verifyState(this);
3772             if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
3773                 throw new Error("Refused to set unsafe header \"" + header + "\"");
3774             }
3776             if (this.requestHeaders[header]) {
3777                 this.requestHeaders[header] += "," + value;
3778             } else {
3779                 this.requestHeaders[header] = value;
3780             }
3781         },
3783         // Helps testing
3784         setResponseHeaders: function setResponseHeaders(headers) {
3785             this.responseHeaders = {};
3787             for (var header in headers) {
3788                 if (headers.hasOwnProperty(header)) {
3789                     this.responseHeaders[header] = headers[header];
3790                 }
3791             }
3793             if (this.async) {
3794                 this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
3795             } else {
3796                 this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
3797             }
3798         },
3800         // Currently treats ALL data as a DOMString (i.e. no Document)
3801         send: function send(data) {
3802             verifyState(this);
3804             if (!/^(get|head)$/i.test(this.method)) {
3805                 if (this.requestHeaders["Content-Type"]) {
3806                     var value = this.requestHeaders["Content-Type"].split(";");
3807                     this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
3808                 } else {
3809                     this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
3810                 }
3812                 this.requestBody = data;
3813             }
3815             this.errorFlag = false;
3816             this.sendFlag = this.async;
3817             this.readyStateChange(FakeXMLHttpRequest.OPENED);
3819             if (typeof this.onSend == "function") {
3820                 this.onSend(this);
3821             }
3823             this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
3824         },
3826         abort: function abort() {
3827             this.aborted = true;
3828             this.responseText = null;
3829             this.errorFlag = true;
3830             this.requestHeaders = {};
3832             if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
3833                 this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
3834                 this.sendFlag = false;
3835             }
3837             this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
3839             this.dispatchEvent(new sinon.Event("abort", false, false, this));
3841             this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
3843             if (typeof this.onerror === "function") {
3844                 this.onerror();
3845             }
3846         },
3848         getResponseHeader: function getResponseHeader(header) {
3849             if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
3850                 return null;
3851             }
3853             if (/^Set-Cookie2?$/i.test(header)) {
3854                 return null;
3855             }
3857             header = header.toLowerCase();
3859             for (var h in this.responseHeaders) {
3860                 if (h.toLowerCase() == header) {
3861                     return this.responseHeaders[h];
3862                 }
3863             }
3865             return null;
3866         },
3868         getAllResponseHeaders: function getAllResponseHeaders() {
3869             if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
3870                 return "";
3871             }
3873             var headers = "";
3875             for (var header in this.responseHeaders) {
3876                 if (this.responseHeaders.hasOwnProperty(header) &&
3877                     !/^Set-Cookie2?$/i.test(header)) {
3878                     headers += header + ": " + this.responseHeaders[header] + "\r\n";
3879                 }
3880             }
3882             return headers;
3883         },
3885         setResponseBody: function setResponseBody(body) {
3886             verifyRequestSent(this);
3887             verifyHeadersReceived(this);
3888             verifyResponseBodyType(body);
3890             var chunkSize = this.chunkSize || 10;
3891             var index = 0;
3892             this.responseText = "";
3894             do {
3895                 if (this.async) {
3896                     this.readyStateChange(FakeXMLHttpRequest.LOADING);
3897                 }
3899                 this.responseText += body.substring(index, index + chunkSize);
3900                 index += chunkSize;
3901             } while (index < body.length);
3903             var type = this.getResponseHeader("Content-Type");
3905             if (this.responseText &&
3906                 (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
3907                 try {
3908                     this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
3909                 } catch (e) {
3910                     // Unable to parse XML - no biggie
3911                 }
3912             }
3914             if (this.async) {
3915                 this.readyStateChange(FakeXMLHttpRequest.DONE);
3916             } else {
3917                 this.readyState = FakeXMLHttpRequest.DONE;
3918             }
3919         },
3921         respond: function respond(status, headers, body) {
3922             this.status = typeof status == "number" ? status : 200;
3923             this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
3924             this.setResponseHeaders(headers || {});
3925             this.setResponseBody(body || "");
3926         },
3928         uploadProgress: function uploadProgress(progressEventRaw) {
3929             if (supportsProgress) {
3930                 this.upload.dispatchEvent(new sinon.Event("progress", progressEventRaw));
3931             }
3932         },
3934         uploadError: function uploadError(error) {
3935             if (supportsCustomEvent) {
3936                 this.upload.dispatchEvent(new sinon.Event("error", {"detail": error}));
3937             }
3938         }
3939     });
3941     sinon.extend(FakeXMLHttpRequest, {
3942         UNSENT: 0,
3943         OPENED: 1,
3944         HEADERS_RECEIVED: 2,
3945         LOADING: 3,
3946         DONE: 4
3947     });
3949     // Borrowed from JSpec
3950     FakeXMLHttpRequest.parseXML = function parseXML(text) {
3951         var xmlDoc;
3953         if (typeof DOMParser != "undefined") {
3954             var parser = new DOMParser();
3955             xmlDoc = parser.parseFromString(text, "text/xml");
3956         } else {
3957             xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
3958             xmlDoc.async = "false";
3959             xmlDoc.loadXML(text);
3960         }
3962         return xmlDoc;
3963     };
3965     FakeXMLHttpRequest.statusCodes = {
3966         100: "Continue",
3967         101: "Switching Protocols",
3968         200: "OK",
3969         201: "Created",
3970         202: "Accepted",
3971         203: "Non-Authoritative Information",
3972         204: "No Content",
3973         205: "Reset Content",
3974         206: "Partial Content",
3975         300: "Multiple Choice",
3976         301: "Moved Permanently",
3977         302: "Found",
3978         303: "See Other",
3979         304: "Not Modified",
3980         305: "Use Proxy",
3981         307: "Temporary Redirect",
3982         400: "Bad Request",
3983         401: "Unauthorized",
3984         402: "Payment Required",
3985         403: "Forbidden",
3986         404: "Not Found",
3987         405: "Method Not Allowed",
3988         406: "Not Acceptable",
3989         407: "Proxy Authentication Required",
3990         408: "Request Timeout",
3991         409: "Conflict",
3992         410: "Gone",
3993         411: "Length Required",
3994         412: "Precondition Failed",
3995         413: "Request Entity Too Large",
3996         414: "Request-URI Too Long",
3997         415: "Unsupported Media Type",
3998         416: "Requested Range Not Satisfiable",
3999         417: "Expectation Failed",
4000         422: "Unprocessable Entity",
4001         500: "Internal Server Error",
4002         501: "Not Implemented",
4003         502: "Bad Gateway",
4004         503: "Service Unavailable",
4005         504: "Gateway Timeout",
4006         505: "HTTP Version Not Supported"
4007     };
4009     sinon.useFakeXMLHttpRequest = function () {
4010         sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
4011             if (xhr.supportsXHR) {
4012                 global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
4013             }
4015             if (xhr.supportsActiveX) {
4016                 global.ActiveXObject = xhr.GlobalActiveXObject;
4017             }
4019             delete sinon.FakeXMLHttpRequest.restore;
4021             if (keepOnCreate !== true) {
4022                 delete sinon.FakeXMLHttpRequest.onCreate;
4023             }
4024         };
4025         if (xhr.supportsXHR) {
4026             global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
4027         }
4029         if (xhr.supportsActiveX) {
4030             global.ActiveXObject = function ActiveXObject(objId) {
4031                 if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
4033                     return new sinon.FakeXMLHttpRequest();
4034                 }
4036                 return new xhr.GlobalActiveXObject(objId);
4037             };
4038         }
4040         return sinon.FakeXMLHttpRequest;
4041     };
4043     sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
4045 })(typeof global === "object" ? global : this);
4047 if (typeof module !== 'undefined' && module.exports) {
4048     module.exports = sinon;
4052  * @depend fake_xml_http_request.js
4053  */
4054 /*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
4055 /*global module, require, window*/
4057  * The Sinon "server" mimics a web server that receives requests from
4058  * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
4059  * both synchronously and asynchronously. To respond synchronuously, canned
4060  * answers have to be provided upfront.
4062  * @author Christian Johansen (christian@cjohansen.no)
4063  * @license BSD
4065  * Copyright (c) 2010-2013 Christian Johansen
4066  */
4068 if (typeof sinon == "undefined") {
4069     var sinon = {};
4072 sinon.fakeServer = (function () {
4073     var push = [].push;
4074     function F() {}
4076     function create(proto) {
4077         F.prototype = proto;
4078         return new F();
4079     }
4081     function responseArray(handler) {
4082         var response = handler;
4084         if (Object.prototype.toString.call(handler) != "[object Array]") {
4085             response = [200, {}, handler];
4086         }
4088         if (typeof response[2] != "string") {
4089             throw new TypeError("Fake server response body should be string, but was " +
4090                                 typeof response[2]);
4091         }
4093         return response;
4094     }
4096     var wloc = typeof window !== "undefined" ? window.location : {};
4097     var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
4099     function matchOne(response, reqMethod, reqUrl) {
4100         var rmeth = response.method;
4101         var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
4102         var url = response.url;
4103         var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
4105         return matchMethod && matchUrl;
4106     }
4108     function match(response, request) {
4109         var requestUrl = request.url;
4111         if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
4112             requestUrl = requestUrl.replace(rCurrLoc, "");
4113         }
4115         if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
4116             if (typeof response.response == "function") {
4117                 var ru = response.url;
4118                 var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
4119                 return response.response.apply(response, args);
4120             }
4122             return true;
4123         }
4125         return false;
4126     }
4128     function log(response, request) {
4129         var str;
4131         str =  "Request:\n"  + sinon.format(request)  + "\n\n";
4132         str += "Response:\n" + sinon.format(response) + "\n\n";
4134         sinon.log(str);
4135     }
4137     return {
4138         create: function () {
4139             var server = create(this);
4140             this.xhr = sinon.useFakeXMLHttpRequest();
4141             server.requests = [];
4143             this.xhr.onCreate = function (xhrObj) {
4144                 server.addRequest(xhrObj);
4145             };
4147             return server;
4148         },
4150         addRequest: function addRequest(xhrObj) {
4151             var server = this;
4152             push.call(this.requests, xhrObj);
4154             xhrObj.onSend = function () {
4155                 server.handleRequest(this);
4157                 if (server.autoRespond && !server.responding) {
4158                     setTimeout(function () {
4159                         server.responding = false;
4160                         server.respond();
4161                     }, server.autoRespondAfter || 10);
4163                     server.responding = true;
4164                 }
4165             };
4166         },
4168         getHTTPMethod: function getHTTPMethod(request) {
4169             if (this.fakeHTTPMethods && /post/i.test(request.method)) {
4170                 var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
4171                 return !!matches ? matches[1] : request.method;
4172             }
4174             return request.method;
4175         },
4177         handleRequest: function handleRequest(xhr) {
4178             if (xhr.async) {
4179                 if (!this.queue) {
4180                     this.queue = [];
4181                 }
4183                 push.call(this.queue, xhr);
4184             } else {
4185                 this.processRequest(xhr);
4186             }
4187         },
4189         respondWith: function respondWith(method, url, body) {
4190             if (arguments.length == 1 && typeof method != "function") {
4191                 this.response = responseArray(method);
4192                 return;
4193             }
4195             if (!this.responses) { this.responses = []; }
4197             if (arguments.length == 1) {
4198                 body = method;
4199                 url = method = null;
4200             }
4202             if (arguments.length == 2) {
4203                 body = url;
4204                 url = method;
4205                 method = null;
4206             }
4208             push.call(this.responses, {
4209                 method: method,
4210                 url: url,
4211                 response: typeof body == "function" ? body : responseArray(body)
4212             });
4213         },
4215         respond: function respond() {
4216             if (arguments.length > 0) this.respondWith.apply(this, arguments);
4217             var queue = this.queue || [];
4218             var requests = queue.splice(0);
4219             var request;
4221             while(request = requests.shift()) {
4222                 this.processRequest(request);
4223             }
4224         },
4226         processRequest: function processRequest(request) {
4227             try {
4228                 if (request.aborted) {
4229                     return;
4230                 }
4232                 var response = this.response || [404, {}, ""];
4234                 if (this.responses) {
4235                     for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
4236                         if (match.call(this, this.responses[i], request)) {
4237                             response = this.responses[i].response;
4238                             break;
4239                         }
4240                     }
4241                 }
4243                 if (request.readyState != 4) {
4244                     log(response, request);
4246                     request.respond(response[0], response[1], response[2]);
4247                 }
4248             } catch (e) {
4249                 sinon.logError("Fake server request processing", e);
4250             }
4251         },
4253         restore: function restore() {
4254             return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
4255         }
4256     };
4257 }());
4259 if (typeof module !== 'undefined' && module.exports) {
4260     module.exports = sinon;
4264  * @depend fake_server.js
4265  * @depend fake_timers.js
4266  */
4267 /*jslint browser: true, eqeqeq: false, onevar: false*/
4268 /*global sinon*/
4270  * Add-on for sinon.fakeServer that automatically handles a fake timer along with
4271  * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
4272  * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
4273  * it polls the object for completion with setInterval. Dispite the direct
4274  * motivation, there is nothing jQuery-specific in this file, so it can be used
4275  * in any environment where the ajax implementation depends on setInterval or
4276  * setTimeout.
4278  * @author Christian Johansen (christian@cjohansen.no)
4279  * @license BSD
4281  * Copyright (c) 2010-2013 Christian Johansen
4282  */
4284 (function () {
4285     function Server() {}
4286     Server.prototype = sinon.fakeServer;
4288     sinon.fakeServerWithClock = new Server();
4290     sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
4291         if (xhr.async) {
4292             if (typeof setTimeout.clock == "object") {
4293                 this.clock = setTimeout.clock;
4294             } else {
4295                 this.clock = sinon.useFakeTimers();
4296                 this.resetClock = true;
4297             }
4299             if (!this.longestTimeout) {
4300                 var clockSetTimeout = this.clock.setTimeout;
4301                 var clockSetInterval = this.clock.setInterval;
4302                 var server = this;
4304                 this.clock.setTimeout = function (fn, timeout) {
4305                     server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
4307                     return clockSetTimeout.apply(this, arguments);
4308                 };
4310                 this.clock.setInterval = function (fn, timeout) {
4311                     server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
4313                     return clockSetInterval.apply(this, arguments);
4314                 };
4315             }
4316         }
4318         return sinon.fakeServer.addRequest.call(this, xhr);
4319     };
4321     sinon.fakeServerWithClock.respond = function respond() {
4322         var returnVal = sinon.fakeServer.respond.apply(this, arguments);
4324         if (this.clock) {
4325             this.clock.tick(this.longestTimeout || 0);
4326             this.longestTimeout = 0;
4328             if (this.resetClock) {
4329                 this.clock.restore();
4330                 this.resetClock = false;
4331             }
4332         }
4334         return returnVal;
4335     };
4337     sinon.fakeServerWithClock.restore = function restore() {
4338         if (this.clock) {
4339             this.clock.restore();
4340         }
4342         return sinon.fakeServer.restore.apply(this, arguments);
4343     };
4344 }());
4347  * @depend ../sinon.js
4348  * @depend collection.js
4349  * @depend util/fake_timers.js
4350  * @depend util/fake_server_with_clock.js
4351  */
4352 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
4353 /*global require, module*/
4355  * Manages fake collections as well as fake utilities such as Sinon's
4356  * timers and fake XHR implementation in one convenient object.
4358  * @author Christian Johansen (christian@cjohansen.no)
4359  * @license BSD
4361  * Copyright (c) 2010-2013 Christian Johansen
4362  */
4364 if (typeof module !== 'undefined' && module.exports) {
4365     var sinon = require("../sinon");
4366     sinon.extend(sinon, require("./util/fake_timers"));
4369 (function () {
4370     var push = [].push;
4372     function exposeValue(sandbox, config, key, value) {
4373         if (!value) {
4374             return;
4375         }
4377         if (config.injectInto && !(key in config.injectInto)) {
4378             config.injectInto[key] = value;
4379             sandbox.injectedKeys.push(key);
4380         } else {
4381             push.call(sandbox.args, value);
4382         }
4383     }
4385     function prepareSandboxFromConfig(config) {
4386         var sandbox = sinon.create(sinon.sandbox);
4388         if (config.useFakeServer) {
4389             if (typeof config.useFakeServer == "object") {
4390                 sandbox.serverPrototype = config.useFakeServer;
4391             }
4393             sandbox.useFakeServer();
4394         }
4396         if (config.useFakeTimers) {
4397             if (typeof config.useFakeTimers == "object") {
4398                 sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
4399             } else {
4400                 sandbox.useFakeTimers();
4401             }
4402         }
4404         return sandbox;
4405     }
4407     sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
4408         useFakeTimers: function useFakeTimers() {
4409             this.clock = sinon.useFakeTimers.apply(sinon, arguments);
4411             return this.add(this.clock);
4412         },
4414         serverPrototype: sinon.fakeServer,
4416         useFakeServer: function useFakeServer() {
4417             var proto = this.serverPrototype || sinon.fakeServer;
4419             if (!proto || !proto.create) {
4420                 return null;
4421             }
4423             this.server = proto.create();
4424             return this.add(this.server);
4425         },
4427         inject: function (obj) {
4428             sinon.collection.inject.call(this, obj);
4430             if (this.clock) {
4431                 obj.clock = this.clock;
4432             }
4434             if (this.server) {
4435                 obj.server = this.server;
4436                 obj.requests = this.server.requests;
4437             }
4439             return obj;
4440         },
4442         restore: function () {
4443             sinon.collection.restore.apply(this, arguments);
4444             this.restoreContext();
4445         },
4447         restoreContext: function () {
4448             if (this.injectedKeys) {
4449                 for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
4450                     delete this.injectInto[this.injectedKeys[i]];
4451                 }
4452                 this.injectedKeys = [];
4453             }
4454         },
4456         create: function (config) {
4457             if (!config) {
4458                 return sinon.create(sinon.sandbox);
4459             }
4461             var sandbox = prepareSandboxFromConfig(config);
4462             sandbox.args = sandbox.args || [];
4463             sandbox.injectedKeys = [];
4464             sandbox.injectInto = config.injectInto;
4465             var prop, value, exposed = sandbox.inject({});
4467             if (config.properties) {
4468                 for (var i = 0, l = config.properties.length; i < l; i++) {
4469                     prop = config.properties[i];
4470                     value = exposed[prop] || prop == "sandbox" && sandbox;
4471                     exposeValue(sandbox, config, prop, value);
4472                 }
4473             } else {
4474                 exposeValue(sandbox, config, "sandbox", value);
4475             }
4477             return sandbox;
4478         }
4479     });
4481     sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
4483     if (typeof module !== 'undefined' && module.exports) {
4484         module.exports = sinon.sandbox;
4485     }
4486 }());
4489  * @depend ../sinon.js
4490  * @depend stub.js
4491  * @depend mock.js
4492  * @depend sandbox.js
4493  */
4494 /*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
4495 /*global module, require, sinon*/
4497  * Test function, sandboxes fakes
4499  * @author Christian Johansen (christian@cjohansen.no)
4500  * @license BSD
4502  * Copyright (c) 2010-2013 Christian Johansen
4503  */
4505 (function (sinon) {
4506     var commonJSModule = typeof module !== 'undefined' && module.exports;
4508     if (!sinon && commonJSModule) {
4509         sinon = require("../sinon");
4510     }
4512     if (!sinon) {
4513         return;
4514     }
4516     function test(callback) {
4517         var type = typeof callback;
4519         if (type != "function") {
4520             throw new TypeError("sinon.test needs to wrap a test function, got " + type);
4521         }
4523         return function () {
4524             var config = sinon.getConfig(sinon.config);
4525             config.injectInto = config.injectIntoThis && this || config.injectInto;
4526             var sandbox = sinon.sandbox.create(config);
4527             var exception, result;
4528             var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
4530             try {
4531                 result = callback.apply(this, args);
4532             } catch (e) {
4533                 exception = e;
4534             }
4536             if (typeof exception !== "undefined") {
4537                 sandbox.restore();
4538                 throw exception;
4539             }
4540             else {
4541                 sandbox.verifyAndRestore();
4542             }
4544             return result;
4545         };
4546     }
4548     test.config = {
4549         injectIntoThis: true,
4550         injectInto: null,
4551         properties: ["spy", "stub", "mock", "clock", "server", "requests"],
4552         useFakeTimers: true,
4553         useFakeServer: true
4554     };
4556     if (commonJSModule) {
4557         module.exports = test;
4558     } else {
4559         sinon.test = test;
4560     }
4561 }(typeof sinon == "object" && sinon || null));
4564  * @depend ../sinon.js
4565  * @depend test.js
4566  */
4567 /*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
4568 /*global module, require, sinon*/
4570  * Test case, sandboxes all test functions
4572  * @author Christian Johansen (christian@cjohansen.no)
4573  * @license BSD
4575  * Copyright (c) 2010-2013 Christian Johansen
4576  */
4578 (function (sinon) {
4579     var commonJSModule = typeof module !== 'undefined' && module.exports;
4581     if (!sinon && commonJSModule) {
4582         sinon = require("../sinon");
4583     }
4585     if (!sinon || !Object.prototype.hasOwnProperty) {
4586         return;
4587     }
4589     function createTest(property, setUp, tearDown) {
4590         return function () {
4591             if (setUp) {
4592                 setUp.apply(this, arguments);
4593             }
4595             var exception, result;
4597             try {
4598                 result = property.apply(this, arguments);
4599             } catch (e) {
4600                 exception = e;
4601             }
4603             if (tearDown) {
4604                 tearDown.apply(this, arguments);
4605             }
4607             if (exception) {
4608                 throw exception;
4609             }
4611             return result;
4612         };
4613     }
4615     function testCase(tests, prefix) {
4616         /*jsl:ignore*/
4617         if (!tests || typeof tests != "object") {
4618             throw new TypeError("sinon.testCase needs an object with test functions");
4619         }
4620         /*jsl:end*/
4622         prefix = prefix || "test";
4623         var rPrefix = new RegExp("^" + prefix);
4624         var methods = {}, testName, property, method;
4625         var setUp = tests.setUp;
4626         var tearDown = tests.tearDown;
4628         for (testName in tests) {
4629             if (tests.hasOwnProperty(testName)) {
4630                 property = tests[testName];
4632                 if (/^(setUp|tearDown)$/.test(testName)) {
4633                     continue;
4634                 }
4636                 if (typeof property == "function" && rPrefix.test(testName)) {
4637                     method = property;
4639                     if (setUp || tearDown) {
4640                         method = createTest(property, setUp, tearDown);
4641                     }
4643                     methods[testName] = sinon.test(method);
4644                 } else {
4645                     methods[testName] = tests[testName];
4646                 }
4647             }
4648         }
4650         return methods;
4651     }
4653     if (commonJSModule) {
4654         module.exports = testCase;
4655     } else {
4656         sinon.testCase = testCase;
4657     }
4658 }(typeof sinon == "object" && sinon || null));
4661  * @depend ../sinon.js
4662  * @depend stub.js
4663  */
4664 /*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
4665 /*global module, require, sinon*/
4667  * Assertions matching the test spy retrieval interface.
4669  * @author Christian Johansen (christian@cjohansen.no)
4670  * @license BSD
4672  * Copyright (c) 2010-2013 Christian Johansen
4673  */
4675 (function (sinon, global) {
4676     var commonJSModule = typeof module !== "undefined" && module.exports;
4677     var slice = Array.prototype.slice;
4678     var assert;
4680     if (!sinon && commonJSModule) {
4681         sinon = require("../sinon");
4682     }
4684     if (!sinon) {
4685         return;
4686     }
4688     function verifyIsStub() {
4689         var method;
4691         for (var i = 0, l = arguments.length; i < l; ++i) {
4692             method = arguments[i];
4694             if (!method) {
4695                 assert.fail("fake is not a spy");
4696             }
4698             if (typeof method != "function") {
4699                 assert.fail(method + " is not a function");
4700             }
4702             if (typeof method.getCall != "function") {
4703                 assert.fail(method + " is not stubbed");
4704             }
4705         }
4706     }
4708     function failAssertion(object, msg) {
4709         object = object || global;
4710         var failMethod = object.fail || assert.fail;
4711         failMethod.call(object, msg);
4712     }
4714     function mirrorPropAsAssertion(name, method, message) {
4715         if (arguments.length == 2) {
4716             message = method;
4717             method = name;
4718         }
4720         assert[name] = function (fake) {
4721             verifyIsStub(fake);
4723             var args = slice.call(arguments, 1);
4724             var failed = false;
4726             if (typeof method == "function") {
4727                 failed = !method(fake);
4728             } else {
4729                 failed = typeof fake[method] == "function" ?
4730                     !fake[method].apply(fake, args) : !fake[method];
4731             }
4733             if (failed) {
4734                 failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
4735             } else {
4736                 assert.pass(name);
4737             }
4738         };
4739     }
4741     function exposedName(prefix, prop) {
4742         return !prefix || /^fail/.test(prop) ? prop :
4743             prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
4744     }
4746     assert = {
4747         failException: "AssertError",
4749         fail: function fail(message) {
4750             var error = new Error(message);
4751             error.name = this.failException || assert.failException;
4753             throw error;
4754         },
4756         pass: function pass(assertion) {},
4758         callOrder: function assertCallOrder() {
4759             verifyIsStub.apply(null, arguments);
4760             var expected = "", actual = "";
4762             if (!sinon.calledInOrder(arguments)) {
4763                 try {
4764                     expected = [].join.call(arguments, ", ");
4765                     var calls = slice.call(arguments);
4766                     var i = calls.length;
4767                     while (i) {
4768                         if (!calls[--i].called) {
4769                             calls.splice(i, 1);
4770                         }
4771                     }
4772                     actual = sinon.orderByFirstCall(calls).join(", ");
4773                 } catch (e) {
4774                     // If this fails, we'll just fall back to the blank string
4775                 }
4777                 failAssertion(this, "expected " + expected + " to be " +
4778                               "called in order but were called as " + actual);
4779             } else {
4780                 assert.pass("callOrder");
4781             }
4782         },
4784         callCount: function assertCallCount(method, count) {
4785             verifyIsStub(method);
4787             if (method.callCount != count) {
4788                 var msg = "expected %n to be called " + sinon.timesInWords(count) +
4789                     " but was called %c%C";
4790                 failAssertion(this, method.printf(msg));
4791             } else {
4792                 assert.pass("callCount");
4793             }
4794         },
4796         expose: function expose(target, options) {
4797             if (!target) {
4798                 throw new TypeError("target is null or undefined");
4799             }
4801             var o = options || {};
4802             var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
4803             var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
4805             for (var method in this) {
4806                 if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
4807                     target[exposedName(prefix, method)] = this[method];
4808                 }
4809             }
4811             return target;
4812         }
4813     };
4815     mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
4816     mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
4817                           "expected %n to not have been called but was called %c%C");
4818     mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
4819     mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
4820     mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
4821     mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
4822     mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
4823     mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
4824     mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
4825     mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
4826     mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
4827     mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
4828     mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
4829     mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
4830     mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
4831     mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
4832     mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
4833     mirrorPropAsAssertion("threw", "%n did not throw exception%C");
4834     mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
4836     if (commonJSModule) {
4837         module.exports = assert;
4838     } else {
4839         sinon.assert = assert;
4840     }
4841 }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
4843 return sinon;}.call(typeof window != 'undefined' && window || {}));