editor: status bar
[fnpeditor.git] / libs / sinon-1.7.3.js
1 /**
2  * Sinon.JS 1.7.3, 2013/06/20
3  *
4  * @author Christian Johansen (christian@cjohansen.no)
5  * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
6  *
7  * (The BSD License)
8  * 
9  * Copyright (c) 2010-2013, Christian Johansen, christian@cjohansen.no
10  * All rights reserved.
11  * 
12  * Redistribution and use in source and binary forms, with or without modification,
13  * are permitted provided that the following conditions are met:
14  * 
15  *     * Redistributions of source code must retain the above copyright notice,
16  *       this list of conditions and the following disclaimer.
17  *     * Redistributions in binary form must reproduce the above copyright notice,
18  *       this list of conditions and the following disclaimer in the documentation
19  *       and/or other materials provided with the distribution.
20  *     * Neither the name of Christian Johansen nor the names of his contributors
21  *       may be used to endorse or promote products derived from this software
22  *       without specific prior written permission.
23  * 
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 this.sinon = (function () {
37 var buster = (function (setTimeout, B) {
38     var isNode = typeof require == "function" && typeof module == "object";
39     var div = typeof document != "undefined" && document.createElement("div");
40     var F = function () {};
41
42     var buster = {
43         bind: function bind(obj, methOrProp) {
44             var method = typeof methOrProp == "string" ? obj[methOrProp] : methOrProp;
45             var args = Array.prototype.slice.call(arguments, 2);
46             return function () {
47                 var allArgs = args.concat(Array.prototype.slice.call(arguments));
48                 return method.apply(obj, allArgs);
49             };
50         },
51
52         partial: function partial(fn) {
53             var args = [].slice.call(arguments, 1);
54             return function () {
55                 return fn.apply(this, args.concat([].slice.call(arguments)));
56             };
57         },
58
59         create: function create(object) {
60             F.prototype = object;
61             return new F();
62         },
63
64         extend: function extend(target) {
65             if (!target) { return; }
66             for (var i = 1, l = arguments.length, prop; i < l; ++i) {
67                 for (prop in arguments[i]) {
68                     target[prop] = arguments[i][prop];
69                 }
70             }
71             return target;
72         },
73
74         nextTick: function nextTick(callback) {
75             if (typeof process != "undefined" && process.nextTick) {
76                 return process.nextTick(callback);
77             }
78             setTimeout(callback, 0);
79         },
80
81         functionName: function functionName(func) {
82             if (!func) return "";
83             if (func.displayName) return func.displayName;
84             if (func.name) return func.name;
85             var matches = func.toString().match(/function\s+([^\(]+)/m);
86             return matches && matches[1] || "";
87         },
88
89         isNode: function isNode(obj) {
90             if (!div) return false;
91             try {
92                 obj.appendChild(div);
93                 obj.removeChild(div);
94             } catch (e) {
95                 return false;
96             }
97             return true;
98         },
99
100         isElement: function isElement(obj) {
101             return obj && obj.nodeType === 1 && buster.isNode(obj);
102         },
103
104         isArray: function isArray(arr) {
105             return Object.prototype.toString.call(arr) == "[object Array]";
106         },
107
108         flatten: function flatten(arr) {
109             var result = [], arr = arr || [];
110             for (var i = 0, l = arr.length; i < l; ++i) {
111                 result = result.concat(buster.isArray(arr[i]) ? flatten(arr[i]) : arr[i]);
112             }
113             return result;
114         },
115
116         each: function each(arr, callback) {
117             for (var i = 0, l = arr.length; i < l; ++i) {
118                 callback(arr[i]);
119             }
120         },
121
122         map: function map(arr, callback) {
123             var results = [];
124             for (var i = 0, l = arr.length; i < l; ++i) {
125                 results.push(callback(arr[i]));
126             }
127             return results;
128         },
129
130         parallel: function parallel(fns, callback) {
131             function cb(err, res) {
132                 if (typeof callback == "function") {
133                     callback(err, res);
134                     callback = null;
135                 }
136             }
137             if (fns.length == 0) { return cb(null, []); }
138             var remaining = fns.length, results = [];
139             function makeDone(num) {
140                 return function done(err, result) {
141                     if (err) { return cb(err); }
142                     results[num] = result;
143                     if (--remaining == 0) { cb(null, results); }
144                 };
145             }
146             for (var i = 0, l = fns.length; i < l; ++i) {
147                 fns[i](makeDone(i));
148             }
149         },
150
151         series: function series(fns, callback) {
152             function cb(err, res) {
153                 if (typeof callback == "function") {
154                     callback(err, res);
155                 }
156             }
157             var remaining = fns.slice();
158             var results = [];
159             function callNext() {
160                 if (remaining.length == 0) return cb(null, results);
161                 var promise = remaining.shift()(next);
162                 if (promise && typeof promise.then == "function") {
163                     promise.then(buster.partial(next, null), next);
164                 }
165             }
166             function next(err, result) {
167                 if (err) return cb(err);
168                 results.push(result);
169                 callNext();
170             }
171             callNext();
172         },
173
174         countdown: function countdown(num, done) {
175             return function () {
176                 if (--num == 0) done();
177             };
178         }
179     };
180
181     if (typeof process === "object" &&
182         typeof require === "function" && typeof module === "object") {
183         var crypto = require("crypto");
184         var path = require("path");
185
186         buster.tmpFile = function (fileName) {
187             var hashed = crypto.createHash("sha1");
188             hashed.update(fileName);
189             var tmpfileName = hashed.digest("hex");
190
191             if (process.platform == "win32") {
192                 return path.join(process.env["TEMP"], tmpfileName);
193             } else {
194                 return path.join("/tmp", tmpfileName);
195             }
196         };
197     }
198
199     if (Array.prototype.some) {
200         buster.some = function (arr, fn, thisp) {
201             return arr.some(fn, thisp);
202         };
203     } else {
204         // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
205         buster.some = function (arr, fun, thisp) {
206                         if (arr == null) { throw new TypeError(); }
207             arr = Object(arr);
208             var len = arr.length >>> 0;
209             if (typeof fun !== "function") { throw new TypeError(); }
210
211             for (var i = 0; i < len; i++) {
212                 if (arr.hasOwnProperty(i) && fun.call(thisp, arr[i], i, arr)) {
213                     return true;
214                 }
215             }
216
217             return false;
218         };
219     }
220
221     if (Array.prototype.filter) {
222         buster.filter = function (arr, fn, thisp) {
223             return arr.filter(fn, thisp);
224         };
225     } else {
226         // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
227         buster.filter = function (fn, thisp) {
228                         if (this == null) { throw new TypeError(); }
229
230             var t = Object(this);
231             var len = t.length >>> 0;
232             if (typeof fn != "function") { throw new TypeError(); }
233
234             var res = [];
235             for (var i = 0; i < len; i++) {
236                 if (i in t) {
237                     var val = t[i]; // in case fun mutates this
238                     if (fn.call(thisp, val, i, t)) { res.push(val); }
239                 }
240             }
241
242             return res;
243         };
244     }
245
246     if (isNode) {
247         module.exports = buster;
248         buster.eventEmitter = require("./buster-event-emitter");
249         Object.defineProperty(buster, "defineVersionGetter", {
250             get: function () {
251                 return require("./define-version-getter");
252             }
253         });
254     }
255
256     return buster.extend(B || {}, buster);
257 }(setTimeout, buster));
258 if (typeof buster === "undefined") {
259     var buster = {};
260 }
261
262 if (typeof module === "object" && typeof require === "function") {
263     buster = require("buster-core");
264 }
265
266 buster.format = buster.format || {};
267 buster.format.excludeConstructors = ["Object", /^.$/];
268 buster.format.quoteStrings = true;
269
270 buster.format.ascii = (function () {
271     
272     var hasOwn = Object.prototype.hasOwnProperty;
273
274     var specialObjects = [];
275     if (typeof global != "undefined") {
276         specialObjects.push({ obj: global, value: "[object global]" });
277     }
278     if (typeof document != "undefined") {
279         specialObjects.push({ obj: document, value: "[object HTMLDocument]" });
280     }
281     if (typeof window != "undefined") {
282         specialObjects.push({ obj: window, value: "[object Window]" });
283     }
284
285     function keys(object) {
286         var k = Object.keys && Object.keys(object) || [];
287
288         if (k.length == 0) {
289             for (var prop in object) {
290                 if (hasOwn.call(object, prop)) {
291                     k.push(prop);
292                 }
293             }
294         }
295
296         return k.sort();
297     }
298
299     function isCircular(object, objects) {
300         if (typeof object != "object") {
301             return false;
302         }
303
304         for (var i = 0, l = objects.length; i < l; ++i) {
305             if (objects[i] === object) {
306                 return true;
307             }
308         }
309
310         return false;
311     }
312
313     function ascii(object, processed, indent) {
314         if (typeof object == "string") {
315             var quote = typeof this.quoteStrings != "boolean" || this.quoteStrings;
316             return processed || quote ? '"' + object + '"' : object;
317         }
318
319         if (typeof object == "function" && !(object instanceof RegExp)) {
320             return ascii.func(object);
321         }
322
323         processed = processed || [];
324
325         if (isCircular(object, processed)) {
326             return "[Circular]";
327         }
328
329         if (Object.prototype.toString.call(object) == "[object Array]") {
330             return ascii.array.call(this, object, processed);
331         }
332
333         if (!object) {
334             return "" + object;
335         }
336
337         if (buster.isElement(object)) {
338             return ascii.element(object);
339         }
340
341         if (typeof object.toString == "function" &&
342             object.toString !== Object.prototype.toString) {
343             return object.toString();
344         }
345
346         for (var i = 0, l = specialObjects.length; i < l; i++) {
347             if (object === specialObjects[i].obj) {
348                 return specialObjects[i].value;
349             }
350         }
351
352         return ascii.object.call(this, object, processed, indent);
353     }
354
355     ascii.func = function (func) {
356         return "function " + buster.functionName(func) + "() {}";
357     };
358
359     ascii.array = function (array, processed) {
360         processed = processed || [];
361         processed.push(array);
362         var pieces = [];
363
364         for (var i = 0, l = array.length; i < l; ++i) {
365             pieces.push(ascii.call(this, array[i], processed));
366         }
367
368         return "[" + pieces.join(", ") + "]";
369     };
370
371     ascii.object = function (object, processed, indent) {
372         processed = processed || [];
373         processed.push(object);
374         indent = indent || 0;
375         var pieces = [], properties = keys(object), prop, str, obj;
376         var is = "";
377         var length = 3;
378
379         for (var i = 0, l = indent; i < l; ++i) {
380             is += " ";
381         }
382
383         for (i = 0, l = properties.length; i < l; ++i) {
384             prop = properties[i];
385             obj = object[prop];
386
387             if (isCircular(obj, processed)) {
388                 str = "[Circular]";
389             } else {
390                 str = ascii.call(this, obj, processed, indent + 2);
391             }
392
393             str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
394             length += str.length;
395             pieces.push(str);
396         }
397
398         var cons = ascii.constructorName.call(this, object);
399         var prefix = cons ? "[" + cons + "] " : ""
400
401         return (length + indent) > 80 ?
402             prefix + "{\n  " + is + pieces.join(",\n  " + is) + "\n" + is + "}" :
403             prefix + "{ " + pieces.join(", ") + " }";
404     };
405
406     ascii.element = function (element) {
407         var tagName = element.tagName.toLowerCase();
408         var attrs = element.attributes, attribute, pairs = [], attrName;
409
410         for (var i = 0, l = attrs.length; i < l; ++i) {
411             attribute = attrs.item(i);
412             attrName = attribute.nodeName.toLowerCase().replace("html:", "");
413
414             if (attrName == "contenteditable" && attribute.nodeValue == "inherit") {
415                 continue;
416             }
417
418             if (!!attribute.nodeValue) {
419                 pairs.push(attrName + "=\"" + attribute.nodeValue + "\"");
420             }
421         }
422
423         var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
424         var content = element.innerHTML;
425
426         if (content.length > 20) {
427             content = content.substr(0, 20) + "[...]";
428         }
429
430         var res = formatted + pairs.join(" ") + ">" + content + "</" + tagName + ">";
431
432         return res.replace(/ contentEditable="inherit"/, "");
433     };
434
435     ascii.constructorName = function (object) {
436         var name = buster.functionName(object && object.constructor);
437         var excludes = this.excludeConstructors || buster.format.excludeConstructors || [];
438
439         for (var i = 0, l = excludes.length; i < l; ++i) {
440             if (typeof excludes[i] == "string" && excludes[i] == name) {
441                 return "";
442             } else if (excludes[i].test && excludes[i].test(name)) {
443                 return "";
444             }
445         }
446
447         return name;
448     };
449
450     return ascii;
451 }());
452
453 if (typeof module != "undefined") {
454     module.exports = buster.format;
455 }
456 /*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
457 /*global module, require, __dirname, document*/
458 /**
459  * Sinon core utilities. For internal use only.
460  *
461  * @author Christian Johansen (christian@cjohansen.no)
462  * @license BSD
463  *
464  * Copyright (c) 2010-2013 Christian Johansen
465  */
466
467 var sinon = (function (buster) {
468     var div = typeof document != "undefined" && document.createElement("div");
469     var hasOwn = Object.prototype.hasOwnProperty;
470
471     function isDOMNode(obj) {
472         var success = false;
473
474         try {
475             obj.appendChild(div);
476             success = div.parentNode == obj;
477         } catch (e) {
478             return false;
479         } finally {
480             try {
481                 obj.removeChild(div);
482             } catch (e) {
483                 // Remove failed, not much we can do about that
484             }
485         }
486
487         return success;
488     }
489
490     function isElement(obj) {
491         return div && obj && obj.nodeType === 1 && isDOMNode(obj);
492     }
493
494     function isFunction(obj) {
495         return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
496     }
497
498     function mirrorProperties(target, source) {
499         for (var prop in source) {
500             if (!hasOwn.call(target, prop)) {
501                 target[prop] = source[prop];
502             }
503         }
504     }
505
506     function isRestorable (obj) {
507         return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
508     }
509
510     var sinon = {
511         wrapMethod: function wrapMethod(object, property, method) {
512             if (!object) {
513                 throw new TypeError("Should wrap property of object");
514             }
515
516             if (typeof method != "function") {
517                 throw new TypeError("Method wrapper should be function");
518             }
519
520             var wrappedMethod = object[property];
521
522             if (!isFunction(wrappedMethod)) {
523                 throw new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
524                                     property + " as function");
525             }
526
527             if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
528                 throw new TypeError("Attempted to wrap " + property + " which is already wrapped");
529             }
530
531             if (wrappedMethod.calledBefore) {
532                 var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
533                 throw new TypeError("Attempted to wrap " + property + " which is already " + verb);
534             }
535
536             // IE 8 does not support hasOwnProperty on the window object.
537             var owned = hasOwn.call(object, property);
538             object[property] = method;
539             method.displayName = property;
540
541             method.restore = function () {
542                 // For prototype properties try to reset by delete first.
543                 // If this fails (ex: localStorage on mobile safari) then force a reset
544                 // via direct assignment.
545                 if (!owned) {
546                     delete object[property];
547                 }
548                 if (object[property] === method) {
549                     object[property] = wrappedMethod;
550                 }
551             };
552
553             method.restore.sinon = true;
554             mirrorProperties(method, wrappedMethod);
555
556             return method;
557         },
558
559         extend: function extend(target) {
560             for (var i = 1, l = arguments.length; i < l; i += 1) {
561                 for (var prop in arguments[i]) {
562                     if (arguments[i].hasOwnProperty(prop)) {
563                         target[prop] = arguments[i][prop];
564                     }
565
566                     // DONT ENUM bug, only care about toString
567                     if (arguments[i].hasOwnProperty("toString") &&
568                         arguments[i].toString != target.toString) {
569                         target.toString = arguments[i].toString;
570                     }
571                 }
572             }
573
574             return target;
575         },
576
577         create: function create(proto) {
578             var F = function () {};
579             F.prototype = proto;
580             return new F();
581         },
582
583         deepEqual: function deepEqual(a, b) {
584             if (sinon.match && sinon.match.isMatcher(a)) {
585                 return a.test(b);
586             }
587             if (typeof a != "object" || typeof b != "object") {
588                 return a === b;
589             }
590
591             if (isElement(a) || isElement(b)) {
592                 return a === b;
593             }
594
595             if (a === b) {
596                 return true;
597             }
598
599             if ((a === null && b !== null) || (a !== null && b === null)) {
600                 return false;
601             }
602
603             var aString = Object.prototype.toString.call(a);
604             if (aString != Object.prototype.toString.call(b)) {
605                 return false;
606             }
607
608             if (aString == "[object Array]") {
609                 if (a.length !== b.length) {
610                     return false;
611                 }
612
613                 for (var i = 0, l = a.length; i < l; i += 1) {
614                     if (!deepEqual(a[i], b[i])) {
615                         return false;
616                     }
617                 }
618
619                 return true;
620             }
621
622             if (aString == "[object Date]") {
623                 return a.valueOf() === b.valueOf();
624             }
625
626             var prop, aLength = 0, bLength = 0;
627
628             for (prop in a) {
629                 aLength += 1;
630
631                 if (!deepEqual(a[prop], b[prop])) {
632                     return false;
633                 }
634             }
635
636             for (prop in b) {
637                 bLength += 1;
638             }
639
640             return aLength == bLength;
641         },
642
643         functionName: function functionName(func) {
644             var name = func.displayName || func.name;
645
646             // Use function decomposition as a last resort to get function
647             // name. Does not rely on function decomposition to work - if it
648             // doesn't debugging will be slightly less informative
649             // (i.e. toString will say 'spy' rather than 'myFunc').
650             if (!name) {
651                 var matches = func.toString().match(/function ([^\s\(]+)/);
652                 name = matches && matches[1];
653             }
654
655             return name;
656         },
657
658         functionToString: function toString() {
659             if (this.getCall && this.callCount) {
660                 var thisValue, prop, i = this.callCount;
661
662                 while (i--) {
663                     thisValue = this.getCall(i).thisValue;
664
665                     for (prop in thisValue) {
666                         if (thisValue[prop] === this) {
667                             return prop;
668                         }
669                     }
670                 }
671             }
672
673             return this.displayName || "sinon fake";
674         },
675
676         getConfig: function (custom) {
677             var config = {};
678             custom = custom || {};
679             var defaults = sinon.defaultConfig;
680
681             for (var prop in defaults) {
682                 if (defaults.hasOwnProperty(prop)) {
683                     config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
684                 }
685             }
686
687             return config;
688         },
689
690         format: function (val) {
691             return "" + val;
692         },
693
694         defaultConfig: {
695             injectIntoThis: true,
696             injectInto: null,
697             properties: ["spy", "stub", "mock", "clock", "server", "requests"],
698             useFakeTimers: true,
699             useFakeServer: true
700         },
701
702         timesInWords: function timesInWords(count) {
703             return count == 1 && "once" ||
704                 count == 2 && "twice" ||
705                 count == 3 && "thrice" ||
706                 (count || 0) + " times";
707         },
708
709         calledInOrder: function (spies) {
710             for (var i = 1, l = spies.length; i < l; i++) {
711                 if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
712                     return false;
713                 }
714             }
715
716             return true;
717         },
718
719         orderByFirstCall: function (spies) {
720             return spies.sort(function (a, b) {
721                 // uuid, won't ever be equal
722                 var aCall = a.getCall(0);
723                 var bCall = b.getCall(0);
724                 var aId = aCall && aCall.callId || -1;
725                 var bId = bCall && bCall.callId || -1;
726
727                 return aId < bId ? -1 : 1;
728             });
729         },
730
731         log: function () {},
732
733         logError: function (label, err) {
734             var msg = label + " threw exception: "
735             sinon.log(msg + "[" + err.name + "] " + err.message);
736             if (err.stack) { sinon.log(err.stack); }
737
738             setTimeout(function () {
739                 err.message = msg + err.message;
740                 throw err;
741             }, 0);
742         },
743
744         typeOf: function (value) {
745             if (value === null) {
746                 return "null";
747             }
748             else if (value === undefined) {
749                 return "undefined";
750             }
751             var string = Object.prototype.toString.call(value);
752             return string.substring(8, string.length - 1).toLowerCase();
753         },
754
755         createStubInstance: function (constructor) {
756             if (typeof constructor !== "function") {
757                 throw new TypeError("The constructor should be a function.");
758             }
759             return sinon.stub(sinon.create(constructor.prototype));
760         },
761
762         restore: function (object) {
763             if (object !== null && typeof object === "object") {
764                 for (var prop in object) {
765                     if (isRestorable(object[prop])) {
766                         object[prop].restore();
767                     }
768                 }
769             }
770             else if (isRestorable(object)) {
771                 object.restore();
772             }
773         }
774     };
775
776     var isNode = typeof module == "object" && typeof require == "function";
777
778     if (isNode) {
779         try {
780             buster = { format: require("buster-format") };
781         } catch (e) {}
782         module.exports = sinon;
783         module.exports.spy = require("./sinon/spy");
784         module.exports.stub = require("./sinon/stub");
785         module.exports.mock = require("./sinon/mock");
786         module.exports.collection = require("./sinon/collection");
787         module.exports.assert = require("./sinon/assert");
788         module.exports.sandbox = require("./sinon/sandbox");
789         module.exports.test = require("./sinon/test");
790         module.exports.testCase = require("./sinon/test_case");
791         module.exports.assert = require("./sinon/assert");
792         module.exports.match = require("./sinon/match");
793     }
794
795     if (buster) {
796         var formatter = sinon.create(buster.format);
797         formatter.quoteStrings = false;
798         sinon.format = function () {
799             return formatter.ascii.apply(formatter, arguments);
800         };
801     } else if (isNode) {
802         try {
803             var util = require("util");
804             sinon.format = function (value) {
805                 return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
806             };
807         } catch (e) {
808             /* Node, but no util module - would be very old, but better safe than
809              sorry */
810         }
811     }
812
813     return sinon;
814 }(typeof buster == "object" && buster));
815
816 /* @depend ../sinon.js */
817 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
818 /*global module, require, sinon*/
819 /**
820  * Match functions
821  *
822  * @author Maximilian Antoni (mail@maxantoni.de)
823  * @license BSD
824  *
825  * Copyright (c) 2012 Maximilian Antoni
826  */
827
828 (function (sinon) {
829     var commonJSModule = typeof module == "object" && typeof require == "function";
830
831     if (!sinon && commonJSModule) {
832         sinon = require("../sinon");
833     }
834
835     if (!sinon) {
836         return;
837     }
838
839     function assertType(value, type, name) {
840         var actual = sinon.typeOf(value);
841         if (actual !== type) {
842             throw new TypeError("Expected type of " + name + " to be " +
843                 type + ", but was " + actual);
844         }
845     }
846
847     var matcher = {
848         toString: function () {
849             return this.message;
850         }
851     };
852
853     function isMatcher(object) {
854         return matcher.isPrototypeOf(object);
855     }
856
857     function matchObject(expectation, actual) {
858         if (actual === null || actual === undefined) {
859             return false;
860         }
861         for (var key in expectation) {
862             if (expectation.hasOwnProperty(key)) {
863                 var exp = expectation[key];
864                 var act = actual[key];
865                 if (match.isMatcher(exp)) {
866                     if (!exp.test(act)) {
867                         return false;
868                     }
869                 } else if (sinon.typeOf(exp) === "object") {
870                     if (!matchObject(exp, act)) {
871                         return false;
872                     }
873                 } else if (!sinon.deepEqual(exp, act)) {
874                     return false;
875                 }
876             }
877         }
878         return true;
879     }
880
881     matcher.or = function (m2) {
882         if (!isMatcher(m2)) {
883             throw new TypeError("Matcher expected");
884         }
885         var m1 = this;
886         var or = sinon.create(matcher);
887         or.test = function (actual) {
888             return m1.test(actual) || m2.test(actual);
889         };
890         or.message = m1.message + ".or(" + m2.message + ")";
891         return or;
892     };
893
894     matcher.and = function (m2) {
895         if (!isMatcher(m2)) {
896             throw new TypeError("Matcher expected");
897         }
898         var m1 = this;
899         var and = sinon.create(matcher);
900         and.test = function (actual) {
901             return m1.test(actual) && m2.test(actual);
902         };
903         and.message = m1.message + ".and(" + m2.message + ")";
904         return and;
905     };
906
907     var match = function (expectation, message) {
908         var m = sinon.create(matcher);
909         var type = sinon.typeOf(expectation);
910         switch (type) {
911         case "object":
912             if (typeof expectation.test === "function") {
913                 m.test = function (actual) {
914                     return expectation.test(actual) === true;
915                 };
916                 m.message = "match(" + sinon.functionName(expectation.test) + ")";
917                 return m;
918             }
919             var str = [];
920             for (var key in expectation) {
921                 if (expectation.hasOwnProperty(key)) {
922                     str.push(key + ": " + expectation[key]);
923                 }
924             }
925             m.test = function (actual) {
926                 return matchObject(expectation, actual);
927             };
928             m.message = "match(" + str.join(", ") + ")";
929             break;
930         case "number":
931             m.test = function (actual) {
932                 return expectation == actual;
933             };
934             break;
935         case "string":
936             m.test = function (actual) {
937                 if (typeof actual !== "string") {
938                     return false;
939                 }
940                 return actual.indexOf(expectation) !== -1;
941             };
942             m.message = "match(\"" + expectation + "\")";
943             break;
944         case "regexp":
945             m.test = function (actual) {
946                 if (typeof actual !== "string") {
947                     return false;
948                 }
949                 return expectation.test(actual);
950             };
951             break;
952         case "function":
953             m.test = expectation;
954             if (message) {
955                 m.message = message;
956             } else {
957                 m.message = "match(" + sinon.functionName(expectation) + ")";
958             }
959             break;
960         default:
961             m.test = function (actual) {
962               return sinon.deepEqual(expectation, actual);
963             };
964         }
965         if (!m.message) {
966             m.message = "match(" + expectation + ")";
967         }
968         return m;
969     };
970
971     match.isMatcher = isMatcher;
972
973     match.any = match(function () {
974         return true;
975     }, "any");
976
977     match.defined = match(function (actual) {
978         return actual !== null && actual !== undefined;
979     }, "defined");
980
981     match.truthy = match(function (actual) {
982         return !!actual;
983     }, "truthy");
984
985     match.falsy = match(function (actual) {
986         return !actual;
987     }, "falsy");
988
989     match.same = function (expectation) {
990         return match(function (actual) {
991             return expectation === actual;
992         }, "same(" + expectation + ")");
993     };
994
995     match.typeOf = function (type) {
996         assertType(type, "string", "type");
997         return match(function (actual) {
998             return sinon.typeOf(actual) === type;
999         }, "typeOf(\"" + type + "\")");
1000     };
1001
1002     match.instanceOf = function (type) {
1003         assertType(type, "function", "type");
1004         return match(function (actual) {
1005             return actual instanceof type;
1006         }, "instanceOf(" + sinon.functionName(type) + ")");
1007     };
1008
1009     function createPropertyMatcher(propertyTest, messagePrefix) {
1010         return function (property, value) {
1011             assertType(property, "string", "property");
1012             var onlyProperty = arguments.length === 1;
1013             var message = messagePrefix + "(\"" + property + "\"";
1014             if (!onlyProperty) {
1015                 message += ", " + value;
1016             }
1017             message += ")";
1018             return match(function (actual) {
1019                 if (actual === undefined || actual === null ||
1020                         !propertyTest(actual, property)) {
1021                     return false;
1022                 }
1023                 return onlyProperty || sinon.deepEqual(value, actual[property]);
1024             }, message);
1025         };
1026     }
1027
1028     match.has = createPropertyMatcher(function (actual, property) {
1029         if (typeof actual === "object") {
1030             return property in actual;
1031         }
1032         return actual[property] !== undefined;
1033     }, "has");
1034
1035     match.hasOwn = createPropertyMatcher(function (actual, property) {
1036         return actual.hasOwnProperty(property);
1037     }, "hasOwn");
1038
1039     match.bool = match.typeOf("boolean");
1040     match.number = match.typeOf("number");
1041     match.string = match.typeOf("string");
1042     match.object = match.typeOf("object");
1043     match.func = match.typeOf("function");
1044     match.array = match.typeOf("array");
1045     match.regexp = match.typeOf("regexp");
1046     match.date = match.typeOf("date");
1047
1048     if (commonJSModule) {
1049         module.exports = match;
1050     } else {
1051         sinon.match = match;
1052     }
1053 }(typeof sinon == "object" && sinon || null));
1054
1055 /**
1056   * @depend ../sinon.js
1057   * @depend match.js
1058   */
1059 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
1060 /*global module, require, sinon*/
1061 /**
1062   * Spy calls
1063   *
1064   * @author Christian Johansen (christian@cjohansen.no)
1065   * @author Maximilian Antoni (mail@maxantoni.de)
1066   * @license BSD
1067   *
1068   * Copyright (c) 2010-2013 Christian Johansen
1069   * Copyright (c) 2013 Maximilian Antoni
1070   */
1071
1072 var commonJSModule = typeof module == "object" && typeof require == "function";
1073
1074 if (!this.sinon && commonJSModule) {
1075     var sinon = require("../sinon");
1076 }
1077
1078 (function (sinon) {
1079     function throwYieldError(proxy, text, args) {
1080         var msg = sinon.functionName(proxy) + text;
1081         if (args.length) {
1082             msg += " Received [" + slice.call(args).join(", ") + "]";
1083         }
1084         throw new Error(msg);
1085     }
1086
1087     var slice = Array.prototype.slice;
1088
1089     var callProto = {
1090         calledOn: function calledOn(thisValue) {
1091             if (sinon.match && sinon.match.isMatcher(thisValue)) {
1092                 return thisValue.test(this.thisValue);
1093             }
1094             return this.thisValue === thisValue;
1095         },
1096
1097         calledWith: function calledWith() {
1098             for (var i = 0, l = arguments.length; i < l; i += 1) {
1099                 if (!sinon.deepEqual(arguments[i], this.args[i])) {
1100                     return false;
1101                 }
1102             }
1103
1104             return true;
1105         },
1106
1107         calledWithMatch: function calledWithMatch() {
1108             for (var i = 0, l = arguments.length; i < l; i += 1) {
1109                 var actual = this.args[i];
1110                 var expectation = arguments[i];
1111                 if (!sinon.match || !sinon.match(expectation).test(actual)) {
1112                     return false;
1113                 }
1114             }
1115             return true;
1116         },
1117
1118         calledWithExactly: function calledWithExactly() {
1119             return arguments.length == this.args.length &&
1120                 this.calledWith.apply(this, arguments);
1121         },
1122
1123         notCalledWith: function notCalledWith() {
1124             return !this.calledWith.apply(this, arguments);
1125         },
1126
1127         notCalledWithMatch: function notCalledWithMatch() {
1128             return !this.calledWithMatch.apply(this, arguments);
1129         },
1130
1131         returned: function returned(value) {
1132             return sinon.deepEqual(value, this.returnValue);
1133         },
1134
1135         threw: function threw(error) {
1136             if (typeof error === "undefined" || !this.exception) {
1137                 return !!this.exception;
1138             }
1139
1140             return this.exception === error || this.exception.name === error;
1141         },
1142
1143         calledWithNew: function calledWithNew(thisValue) {
1144             return this.thisValue instanceof this.proxy;
1145         },
1146
1147         calledBefore: function (other) {
1148             return this.callId < other.callId;
1149         },
1150
1151         calledAfter: function (other) {
1152             return this.callId > other.callId;
1153         },
1154
1155         callArg: function (pos) {
1156             this.args[pos]();
1157         },
1158
1159         callArgOn: function (pos, thisValue) {
1160             this.args[pos].apply(thisValue);
1161         },
1162
1163         callArgWith: function (pos) {
1164             this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
1165         },
1166
1167         callArgOnWith: function (pos, thisValue) {
1168             var args = slice.call(arguments, 2);
1169             this.args[pos].apply(thisValue, args);
1170         },
1171
1172         "yield": function () {
1173             this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
1174         },
1175
1176         yieldOn: function (thisValue) {
1177             var args = this.args;
1178             for (var i = 0, l = args.length; i < l; ++i) {
1179                 if (typeof args[i] === "function") {
1180                     args[i].apply(thisValue, slice.call(arguments, 1));
1181                     return;
1182                 }
1183             }
1184             throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
1185         },
1186
1187         yieldTo: function (prop) {
1188             this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
1189         },
1190
1191         yieldToOn: function (prop, thisValue) {
1192             var args = this.args;
1193             for (var i = 0, l = args.length; i < l; ++i) {
1194                 if (args[i] && typeof args[i][prop] === "function") {
1195                     args[i][prop].apply(thisValue, slice.call(arguments, 2));
1196                     return;
1197                 }
1198             }
1199             throwYieldError(this.proxy, " cannot yield to '" + prop +
1200                 "' since no callback was passed.", args);
1201         },
1202
1203         toString: function () {
1204             var callStr = this.proxy.toString() + "(";
1205             var args = [];
1206
1207             for (var i = 0, l = this.args.length; i < l; ++i) {
1208                 args.push(sinon.format(this.args[i]));
1209             }
1210
1211             callStr = callStr + args.join(", ") + ")";
1212
1213             if (typeof this.returnValue != "undefined") {
1214                 callStr += " => " + sinon.format(this.returnValue);
1215             }
1216
1217             if (this.exception) {
1218                 callStr += " !" + this.exception.name;
1219
1220                 if (this.exception.message) {
1221                     callStr += "(" + this.exception.message + ")";
1222                 }
1223             }
1224
1225             return callStr;
1226         }
1227     };
1228
1229     callProto.invokeCallback = callProto.yield;
1230
1231     function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
1232         if (typeof id !== "number") {
1233             throw new TypeError("Call id is not a number");
1234         }
1235         var proxyCall = sinon.create(callProto);
1236         proxyCall.proxy = spy;
1237         proxyCall.thisValue = thisValue;
1238         proxyCall.args = args;
1239         proxyCall.returnValue = returnValue;
1240         proxyCall.exception = exception;
1241         proxyCall.callId = id;
1242
1243         return proxyCall;
1244     };
1245     createSpyCall.toString = callProto.toString; // used by mocks
1246
1247     sinon.spyCall = createSpyCall;
1248 }(typeof sinon == "object" && sinon || null));
1249
1250 /**
1251   * @depend ../sinon.js
1252   */
1253 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
1254 /*global module, require, sinon*/
1255 /**
1256   * Spy functions
1257   *
1258   * @author Christian Johansen (christian@cjohansen.no)
1259   * @license BSD
1260   *
1261   * Copyright (c) 2010-2013 Christian Johansen
1262   */
1263
1264 (function (sinon) {
1265     var commonJSModule = typeof module == "object" && typeof require == "function";
1266     var push = Array.prototype.push;
1267     var slice = Array.prototype.slice;
1268     var callId = 0;
1269
1270     function spy(object, property) {
1271         if (!property && typeof object == "function") {
1272             return spy.create(object);
1273         }
1274
1275         if (!object && !property) {
1276             return spy.create(function () { });
1277         }
1278
1279         var method = object[property];
1280         return sinon.wrapMethod(object, property, spy.create(method));
1281     }
1282
1283     function matchingFake(fakes, args, strict) {
1284         if (!fakes) {
1285             return;
1286         }
1287
1288         var alen = args.length;
1289
1290         for (var i = 0, l = fakes.length; i < l; i++) {
1291             if (fakes[i].matches(args, strict)) {
1292                 return fakes[i];
1293             }
1294         }
1295     }
1296
1297     function incrementCallCount() {
1298         this.called = true;
1299         this.callCount += 1;
1300         this.notCalled = false;
1301         this.calledOnce = this.callCount == 1;
1302         this.calledTwice = this.callCount == 2;
1303         this.calledThrice = this.callCount == 3;
1304     }
1305
1306     function createCallProperties() {
1307         this.firstCall = this.getCall(0);
1308         this.secondCall = this.getCall(1);
1309         this.thirdCall = this.getCall(2);
1310         this.lastCall = this.getCall(this.callCount - 1);
1311     }
1312
1313     var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
1314     function createProxy(func) {
1315         // Retain the function length:
1316         var p;
1317         if (func.length) {
1318             eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
1319                 ") { return p.invoke(func, this, slice.call(arguments)); });");
1320         }
1321         else {
1322             p = function proxy() {
1323                 return p.invoke(func, this, slice.call(arguments));
1324             };
1325         }
1326         return p;
1327     }
1328
1329     var uuid = 0;
1330
1331     // Public API
1332     var spyApi = {
1333         reset: function () {
1334             this.called = false;
1335             this.notCalled = true;
1336             this.calledOnce = false;
1337             this.calledTwice = false;
1338             this.calledThrice = false;
1339             this.callCount = 0;
1340             this.firstCall = null;
1341             this.secondCall = null;
1342             this.thirdCall = null;
1343             this.lastCall = null;
1344             this.args = [];
1345             this.returnValues = [];
1346             this.thisValues = [];
1347             this.exceptions = [];
1348             this.callIds = [];
1349             if (this.fakes) {
1350                 for (var i = 0; i < this.fakes.length; i++) {
1351                     this.fakes[i].reset();
1352                 }
1353             }
1354         },
1355
1356         create: function create(func) {
1357             var name;
1358
1359             if (typeof func != "function") {
1360                 func = function () { };
1361             } else {
1362                 name = sinon.functionName(func);
1363             }
1364
1365             var proxy = createProxy(func);
1366
1367             sinon.extend(proxy, spy);
1368             delete proxy.create;
1369             sinon.extend(proxy, func);
1370
1371             proxy.reset();
1372             proxy.prototype = func.prototype;
1373             proxy.displayName = name || "spy";
1374             proxy.toString = sinon.functionToString;
1375             proxy._create = sinon.spy.create;
1376             proxy.id = "spy#" + uuid++;
1377
1378             return proxy;
1379         },
1380
1381         invoke: function invoke(func, thisValue, args) {
1382             var matching = matchingFake(this.fakes, args);
1383             var exception, returnValue;
1384
1385             incrementCallCount.call(this);
1386             push.call(this.thisValues, thisValue);
1387             push.call(this.args, args);
1388             push.call(this.callIds, callId++);
1389
1390             try {
1391                 if (matching) {
1392                     returnValue = matching.invoke(func, thisValue, args);
1393                 } else {
1394                     returnValue = (this.func || func).apply(thisValue, args);
1395                 }
1396             } catch (e) {
1397                 push.call(this.returnValues, undefined);
1398                 exception = e;
1399                 throw e;
1400             } finally {
1401                 push.call(this.exceptions, exception);
1402             }
1403
1404             push.call(this.returnValues, returnValue);
1405
1406             createCallProperties.call(this);
1407
1408             return returnValue;
1409         },
1410
1411         getCall: function getCall(i) {
1412             if (i < 0 || i >= this.callCount) {
1413                 return null;
1414             }
1415
1416             return sinon.spyCall(this, this.thisValues[i], this.args[i],
1417                                     this.returnValues[i], this.exceptions[i],
1418                                     this.callIds[i]);
1419         },
1420
1421         calledBefore: function calledBefore(spyFn) {
1422             if (!this.called) {
1423                 return false;
1424             }
1425
1426             if (!spyFn.called) {
1427                 return true;
1428             }
1429
1430             return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
1431         },
1432
1433         calledAfter: function calledAfter(spyFn) {
1434             if (!this.called || !spyFn.called) {
1435                 return false;
1436             }
1437
1438             return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
1439         },
1440
1441         withArgs: function () {
1442             var args = slice.call(arguments);
1443
1444             if (this.fakes) {
1445                 var match = matchingFake(this.fakes, args, true);
1446
1447                 if (match) {
1448                     return match;
1449                 }
1450             } else {
1451                 this.fakes = [];
1452             }
1453
1454             var original = this;
1455             var fake = this._create();
1456             fake.matchingAguments = args;
1457             push.call(this.fakes, fake);
1458
1459             fake.withArgs = function () {
1460                 return original.withArgs.apply(original, arguments);
1461             };
1462
1463             for (var i = 0; i < this.args.length; i++) {
1464                 if (fake.matches(this.args[i])) {
1465                     incrementCallCount.call(fake);
1466                     push.call(fake.thisValues, this.thisValues[i]);
1467                     push.call(fake.args, this.args[i]);
1468                     push.call(fake.returnValues, this.returnValues[i]);
1469                     push.call(fake.exceptions, this.exceptions[i]);
1470                     push.call(fake.callIds, this.callIds[i]);
1471                 }
1472             }
1473             createCallProperties.call(fake);
1474
1475             return fake;
1476         },
1477
1478         matches: function (args, strict) {
1479             var margs = this.matchingAguments;
1480
1481             if (margs.length <= args.length &&
1482                 sinon.deepEqual(margs, args.slice(0, margs.length))) {
1483                 return !strict || margs.length == args.length;
1484             }
1485         },
1486
1487         printf: function (format) {
1488             var spy = this;
1489             var args = slice.call(arguments, 1);
1490             var formatter;
1491
1492             return (format || "").replace(/%(.)/g, function (match, specifyer) {
1493                 formatter = spyApi.formatters[specifyer];
1494
1495                 if (typeof formatter == "function") {
1496                     return formatter.call(null, spy, args);
1497                 } else if (!isNaN(parseInt(specifyer), 10)) {
1498                     return sinon.format(args[specifyer - 1]);
1499                 }
1500
1501                 return "%" + specifyer;
1502             });
1503         }
1504     };
1505
1506     function delegateToCalls(method, matchAny, actual, notCalled) {
1507         spyApi[method] = function () {
1508             if (!this.called) {
1509                 if (notCalled) {
1510                     return notCalled.apply(this, arguments);
1511                 }
1512                 return false;
1513             }
1514
1515             var currentCall;
1516             var matches = 0;
1517
1518             for (var i = 0, l = this.callCount; i < l; i += 1) {
1519                 currentCall = this.getCall(i);
1520
1521                 if (currentCall[actual || method].apply(currentCall, arguments)) {
1522                     matches += 1;
1523
1524                     if (matchAny) {
1525                         return true;
1526                     }
1527                 }
1528             }
1529
1530             return matches === this.callCount;
1531         };
1532     }
1533
1534     delegateToCalls("calledOn", true);
1535     delegateToCalls("alwaysCalledOn", false, "calledOn");
1536     delegateToCalls("calledWith", true);
1537     delegateToCalls("calledWithMatch", true);
1538     delegateToCalls("alwaysCalledWith", false, "calledWith");
1539     delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
1540     delegateToCalls("calledWithExactly", true);
1541     delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
1542     delegateToCalls("neverCalledWith", false, "notCalledWith",
1543         function () { return true; });
1544     delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
1545         function () { return true; });
1546     delegateToCalls("threw", true);
1547     delegateToCalls("alwaysThrew", false, "threw");
1548     delegateToCalls("returned", true);
1549     delegateToCalls("alwaysReturned", false, "returned");
1550     delegateToCalls("calledWithNew", true);
1551     delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
1552     delegateToCalls("callArg", false, "callArgWith", function () {
1553         throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
1554     });
1555     spyApi.callArgWith = spyApi.callArg;
1556     delegateToCalls("callArgOn", false, "callArgOnWith", function () {
1557         throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
1558     });
1559     spyApi.callArgOnWith = spyApi.callArgOn;
1560     delegateToCalls("yield", false, "yield", function () {
1561         throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
1562     });
1563     // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
1564     spyApi.invokeCallback = spyApi.yield;
1565     delegateToCalls("yieldOn", false, "yieldOn", function () {
1566         throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
1567     });
1568     delegateToCalls("yieldTo", false, "yieldTo", function (property) {
1569         throw new Error(this.toString() + " cannot yield to '" + property +
1570             "' since it was not yet invoked.");
1571     });
1572     delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
1573         throw new Error(this.toString() + " cannot yield to '" + property +
1574             "' since it was not yet invoked.");
1575     });
1576
1577     spyApi.formatters = {
1578         "c": function (spy) {
1579             return sinon.timesInWords(spy.callCount);
1580         },
1581
1582         "n": function (spy) {
1583             return spy.toString();
1584         },
1585
1586         "C": function (spy) {
1587             var calls = [];
1588
1589             for (var i = 0, l = spy.callCount; i < l; ++i) {
1590                 var stringifiedCall = "    " + spy.getCall(i).toString();
1591                 if (/\n/.test(calls[i - 1])) {
1592                     stringifiedCall = "\n" + stringifiedCall;
1593                 }
1594                 push.call(calls, stringifiedCall);
1595             }
1596
1597             return calls.length > 0 ? "\n" + calls.join("\n") : "";
1598         },
1599
1600         "t": function (spy) {
1601             var objects = [];
1602
1603             for (var i = 0, l = spy.callCount; i < l; ++i) {
1604                 push.call(objects, sinon.format(spy.thisValues[i]));
1605             }
1606
1607             return objects.join(", ");
1608         },
1609
1610         "*": function (spy, args) {
1611             var formatted = [];
1612
1613             for (var i = 0, l = args.length; i < l; ++i) {
1614                 push.call(formatted, sinon.format(args[i]));
1615             }
1616
1617             return formatted.join(", ");
1618         }
1619     };
1620
1621     sinon.extend(spy, spyApi);
1622
1623     spy.spyCall = sinon.spyCall;
1624
1625     if (commonJSModule) {
1626         module.exports = spy;
1627     } else {
1628         sinon.spy = spy;
1629     }
1630 }(typeof sinon == "object" && sinon || null));
1631
1632 /**
1633  * @depend ../sinon.js
1634  * @depend spy.js
1635  */
1636 /*jslint eqeqeq: false, onevar: false*/
1637 /*global module, require, sinon*/
1638 /**
1639  * Stub functions
1640  *
1641  * @author Christian Johansen (christian@cjohansen.no)
1642  * @license BSD
1643  *
1644  * Copyright (c) 2010-2013 Christian Johansen
1645  */
1646
1647 (function (sinon) {
1648     var commonJSModule = typeof module == "object" && typeof require == "function";
1649
1650     if (!sinon && commonJSModule) {
1651         sinon = require("../sinon");
1652     }
1653
1654     if (!sinon) {
1655         return;
1656     }
1657
1658     function stub(object, property, func) {
1659         if (!!func && typeof func != "function") {
1660             throw new TypeError("Custom stub should be function");
1661         }
1662
1663         var wrapper;
1664
1665         if (func) {
1666             wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
1667         } else {
1668             wrapper = stub.create();
1669         }
1670
1671         if (!object && !property) {
1672             return sinon.stub.create();
1673         }
1674
1675         if (!property && !!object && typeof object == "object") {
1676             for (var prop in object) {
1677                 if (typeof object[prop] === "function") {
1678                     stub(object, prop);
1679                 }
1680             }
1681
1682             return object;
1683         }
1684
1685         return sinon.wrapMethod(object, property, wrapper);
1686     }
1687
1688     function getChangingValue(stub, property) {
1689         var index = stub.callCount - 1;
1690         var values = stub[property];
1691         var prop = index in values ? values[index] : values[values.length - 1];
1692         stub[property + "Last"] = prop;
1693
1694         return prop;
1695     }
1696
1697     function getCallback(stub, args) {
1698         var callArgAt = getChangingValue(stub, "callArgAts");
1699
1700         if (callArgAt < 0) {
1701             var callArgProp = getChangingValue(stub, "callArgProps");
1702
1703             for (var i = 0, l = args.length; i < l; ++i) {
1704                 if (!callArgProp && typeof args[i] == "function") {
1705                     return args[i];
1706                 }
1707
1708                 if (callArgProp && args[i] &&
1709                     typeof args[i][callArgProp] == "function") {
1710                     return args[i][callArgProp];
1711                 }
1712             }
1713
1714             return null;
1715         }
1716
1717         return args[callArgAt];
1718     }
1719
1720     var join = Array.prototype.join;
1721
1722     function getCallbackError(stub, func, args) {
1723         if (stub.callArgAtsLast < 0) {
1724             var msg;
1725
1726             if (stub.callArgPropsLast) {
1727                 msg = sinon.functionName(stub) +
1728                     " expected to yield to '" + stub.callArgPropsLast +
1729                     "', but no object with such a property was passed."
1730             } else {
1731                 msg = sinon.functionName(stub) +
1732                             " expected to yield, but no callback was passed."
1733             }
1734
1735             if (args.length > 0) {
1736                 msg += " Received [" + join.call(args, ", ") + "]";
1737             }
1738
1739             return msg;
1740         }
1741
1742         return "argument at index " + stub.callArgAtsLast + " is not a function: " + func;
1743     }
1744
1745     var nextTick = (function () {
1746         if (typeof process === "object" && typeof process.nextTick === "function") {
1747             return process.nextTick;
1748         } else if (typeof setImmediate === "function") {
1749             return setImmediate;
1750         } else {
1751             return function (callback) {
1752                 setTimeout(callback, 0);
1753             };
1754         }
1755     })();
1756
1757     function callCallback(stub, args) {
1758         if (stub.callArgAts.length > 0) {
1759             var func = getCallback(stub, args);
1760
1761             if (typeof func != "function") {
1762                 throw new TypeError(getCallbackError(stub, func, args));
1763             }
1764
1765             var callbackArguments = getChangingValue(stub, "callbackArguments");
1766             var callbackContext = getChangingValue(stub, "callbackContexts");
1767
1768             if (stub.callbackAsync) {
1769                 nextTick(function() {
1770                     func.apply(callbackContext, callbackArguments);
1771                 });
1772             } else {
1773                 func.apply(callbackContext, callbackArguments);
1774             }
1775         }
1776     }
1777
1778     var uuid = 0;
1779
1780     sinon.extend(stub, (function () {
1781         var slice = Array.prototype.slice, proto;
1782
1783         function throwsException(error, message) {
1784             if (typeof error == "string") {
1785                 this.exception = new Error(message || "");
1786                 this.exception.name = error;
1787             } else if (!error) {
1788                 this.exception = new Error("Error");
1789             } else {
1790                 this.exception = error;
1791             }
1792
1793             return this;
1794         }
1795
1796         proto = {
1797             create: function create() {
1798                 var functionStub = function () {
1799
1800                     callCallback(functionStub, arguments);
1801
1802                     if (functionStub.exception) {
1803                         throw functionStub.exception;
1804                     } else if (typeof functionStub.returnArgAt == 'number') {
1805                         return arguments[functionStub.returnArgAt];
1806                     } else if (functionStub.returnThis) {
1807                         return this;
1808                     }
1809                     return functionStub.returnValue;
1810                 };
1811
1812                 functionStub.id = "stub#" + uuid++;
1813                 var orig = functionStub;
1814                 functionStub = sinon.spy.create(functionStub);
1815                 functionStub.func = orig;
1816
1817                 functionStub.callArgAts = [];
1818                 functionStub.callbackArguments = [];
1819                 functionStub.callbackContexts = [];
1820                 functionStub.callArgProps = [];
1821
1822                 sinon.extend(functionStub, stub);
1823                 functionStub._create = sinon.stub.create;
1824                 functionStub.displayName = "stub";
1825                 functionStub.toString = sinon.functionToString;
1826
1827                 return functionStub;
1828             },
1829
1830             resetBehavior: function () {
1831                 var i;
1832
1833                 this.callArgAts = [];
1834                 this.callbackArguments = [];
1835                 this.callbackContexts = [];
1836                 this.callArgProps = [];
1837
1838                 delete this.returnValue;
1839                 delete this.returnArgAt;
1840                 this.returnThis = false;
1841
1842                 if (this.fakes) {
1843                     for (i = 0; i < this.fakes.length; i++) {
1844                         this.fakes[i].resetBehavior();
1845                     }
1846                 }
1847             },
1848
1849             returns: function returns(value) {
1850                 this.returnValue = value;
1851
1852                 return this;
1853             },
1854
1855             returnsArg: function returnsArg(pos) {
1856                 if (typeof pos != "number") {
1857                     throw new TypeError("argument index is not number");
1858                 }
1859
1860                 this.returnArgAt = pos;
1861
1862                 return this;
1863             },
1864
1865             returnsThis: function returnsThis() {
1866                 this.returnThis = true;
1867
1868                 return this;
1869             },
1870
1871             "throws": throwsException,
1872             throwsException: throwsException,
1873
1874             callsArg: function callsArg(pos) {
1875                 if (typeof pos != "number") {
1876                     throw new TypeError("argument index is not number");
1877                 }
1878
1879                 this.callArgAts.push(pos);
1880                 this.callbackArguments.push([]);
1881                 this.callbackContexts.push(undefined);
1882                 this.callArgProps.push(undefined);
1883
1884                 return this;
1885             },
1886
1887             callsArgOn: function callsArgOn(pos, context) {
1888                 if (typeof pos != "number") {
1889                     throw new TypeError("argument index is not number");
1890                 }
1891                 if (typeof context != "object") {
1892                     throw new TypeError("argument context is not an object");
1893                 }
1894
1895                 this.callArgAts.push(pos);
1896                 this.callbackArguments.push([]);
1897                 this.callbackContexts.push(context);
1898                 this.callArgProps.push(undefined);
1899
1900                 return this;
1901             },
1902
1903             callsArgWith: function callsArgWith(pos) {
1904                 if (typeof pos != "number") {
1905                     throw new TypeError("argument index is not number");
1906                 }
1907
1908                 this.callArgAts.push(pos);
1909                 this.callbackArguments.push(slice.call(arguments, 1));
1910                 this.callbackContexts.push(undefined);
1911                 this.callArgProps.push(undefined);
1912
1913                 return this;
1914             },
1915
1916             callsArgOnWith: function callsArgWith(pos, context) {
1917                 if (typeof pos != "number") {
1918                     throw new TypeError("argument index is not number");
1919                 }
1920                 if (typeof context != "object") {
1921                     throw new TypeError("argument context is not an object");
1922                 }
1923
1924                 this.callArgAts.push(pos);
1925                 this.callbackArguments.push(slice.call(arguments, 2));
1926                 this.callbackContexts.push(context);
1927                 this.callArgProps.push(undefined);
1928
1929                 return this;
1930             },
1931
1932             yields: function () {
1933                 this.callArgAts.push(-1);
1934                 this.callbackArguments.push(slice.call(arguments, 0));
1935                 this.callbackContexts.push(undefined);
1936                 this.callArgProps.push(undefined);
1937
1938                 return this;
1939             },
1940
1941             yieldsOn: function (context) {
1942                 if (typeof context != "object") {
1943                     throw new TypeError("argument context is not an object");
1944                 }
1945
1946                 this.callArgAts.push(-1);
1947                 this.callbackArguments.push(slice.call(arguments, 1));
1948                 this.callbackContexts.push(context);
1949                 this.callArgProps.push(undefined);
1950
1951                 return this;
1952             },
1953
1954             yieldsTo: function (prop) {
1955                 this.callArgAts.push(-1);
1956                 this.callbackArguments.push(slice.call(arguments, 1));
1957                 this.callbackContexts.push(undefined);
1958                 this.callArgProps.push(prop);
1959
1960                 return this;
1961             },
1962
1963             yieldsToOn: function (prop, context) {
1964                 if (typeof context != "object") {
1965                     throw new TypeError("argument context is not an object");
1966                 }
1967
1968                 this.callArgAts.push(-1);
1969                 this.callbackArguments.push(slice.call(arguments, 2));
1970                 this.callbackContexts.push(context);
1971                 this.callArgProps.push(prop);
1972
1973                 return this;
1974             }
1975         };
1976
1977         // create asynchronous versions of callsArg* and yields* methods
1978         for (var method in proto) {
1979             // need to avoid creating anotherasync versions of the newly added async methods
1980             if (proto.hasOwnProperty(method) &&
1981                 method.match(/^(callsArg|yields|thenYields$)/) &&
1982                 !method.match(/Async/)) {
1983                 proto[method + 'Async'] = (function (syncFnName) {
1984                     return function () {
1985                         this.callbackAsync = true;
1986                         return this[syncFnName].apply(this, arguments);
1987                     };
1988                 })(method);
1989             }
1990         }
1991
1992         return proto;
1993
1994     }()));
1995
1996     if (commonJSModule) {
1997         module.exports = stub;
1998     } else {
1999         sinon.stub = stub;
2000     }
2001 }(typeof sinon == "object" && sinon || null));
2002
2003 /**
2004  * @depend ../sinon.js
2005  * @depend stub.js
2006  */
2007 /*jslint eqeqeq: false, onevar: false, nomen: false*/
2008 /*global module, require, sinon*/
2009 /**
2010  * Mock functions.
2011  *
2012  * @author Christian Johansen (christian@cjohansen.no)
2013  * @license BSD
2014  *
2015  * Copyright (c) 2010-2013 Christian Johansen
2016  */
2017
2018 (function (sinon) {
2019     var commonJSModule = typeof module == "object" && typeof require == "function";
2020     var push = [].push;
2021
2022     if (!sinon && commonJSModule) {
2023         sinon = require("../sinon");
2024     }
2025
2026     if (!sinon) {
2027         return;
2028     }
2029
2030     function mock(object) {
2031         if (!object) {
2032             return sinon.expectation.create("Anonymous mock");
2033         }
2034
2035         return mock.create(object);
2036     }
2037
2038     sinon.mock = mock;
2039
2040     sinon.extend(mock, (function () {
2041         function each(collection, callback) {
2042             if (!collection) {
2043                 return;
2044             }
2045
2046             for (var i = 0, l = collection.length; i < l; i += 1) {
2047                 callback(collection[i]);
2048             }
2049         }
2050
2051         return {
2052             create: function create(object) {
2053                 if (!object) {
2054                     throw new TypeError("object is null");
2055                 }
2056
2057                 var mockObject = sinon.extend({}, mock);
2058                 mockObject.object = object;
2059                 delete mockObject.create;
2060
2061                 return mockObject;
2062             },
2063
2064             expects: function expects(method) {
2065                 if (!method) {
2066                     throw new TypeError("method is falsy");
2067                 }
2068
2069                 if (!this.expectations) {
2070                     this.expectations = {};
2071                     this.proxies = [];
2072                 }
2073
2074                 if (!this.expectations[method]) {
2075                     this.expectations[method] = [];
2076                     var mockObject = this;
2077
2078                     sinon.wrapMethod(this.object, method, function () {
2079                         return mockObject.invokeMethod(method, this, arguments);
2080                     });
2081
2082                     push.call(this.proxies, method);
2083                 }
2084
2085                 var expectation = sinon.expectation.create(method);
2086                 push.call(this.expectations[method], expectation);
2087
2088                 return expectation;
2089             },
2090
2091             restore: function restore() {
2092                 var object = this.object;
2093
2094                 each(this.proxies, function (proxy) {
2095                     if (typeof object[proxy].restore == "function") {
2096                         object[proxy].restore();
2097                     }
2098                 });
2099             },
2100
2101             verify: function verify() {
2102                 var expectations = this.expectations || {};
2103                 var messages = [], met = [];
2104
2105                 each(this.proxies, function (proxy) {
2106                     each(expectations[proxy], function (expectation) {
2107                         if (!expectation.met()) {
2108                             push.call(messages, expectation.toString());
2109                         } else {
2110                             push.call(met, expectation.toString());
2111                         }
2112                     });
2113                 });
2114
2115                 this.restore();
2116
2117                 if (messages.length > 0) {
2118                     sinon.expectation.fail(messages.concat(met).join("\n"));
2119                 } else {
2120                     sinon.expectation.pass(messages.concat(met).join("\n"));
2121                 }
2122
2123                 return true;
2124             },
2125
2126             invokeMethod: function invokeMethod(method, thisValue, args) {
2127                 var expectations = this.expectations && this.expectations[method];
2128                 var length = expectations && expectations.length || 0, i;
2129
2130                 for (i = 0; i < length; i += 1) {
2131                     if (!expectations[i].met() &&
2132                         expectations[i].allowsCall(thisValue, args)) {
2133                         return expectations[i].apply(thisValue, args);
2134                     }
2135                 }
2136
2137                 var messages = [], available, exhausted = 0;
2138
2139                 for (i = 0; i < length; i += 1) {
2140                     if (expectations[i].allowsCall(thisValue, args)) {
2141                         available = available || expectations[i];
2142                     } else {
2143                         exhausted += 1;
2144                     }
2145                     push.call(messages, "    " + expectations[i].toString());
2146                 }
2147
2148                 if (exhausted === 0) {
2149                     return available.apply(thisValue, args);
2150                 }
2151
2152                 messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
2153                     proxy: method,
2154                     args: args
2155                 }));
2156
2157                 sinon.expectation.fail(messages.join("\n"));
2158             }
2159         };
2160     }()));
2161
2162     var times = sinon.timesInWords;
2163
2164     sinon.expectation = (function () {
2165         var slice = Array.prototype.slice;
2166         var _invoke = sinon.spy.invoke;
2167
2168         function callCountInWords(callCount) {
2169             if (callCount == 0) {
2170                 return "never called";
2171             } else {
2172                 return "called " + times(callCount);
2173             }
2174         }
2175
2176         function expectedCallCountInWords(expectation) {
2177             var min = expectation.minCalls;
2178             var max = expectation.maxCalls;
2179
2180             if (typeof min == "number" && typeof max == "number") {
2181                 var str = times(min);
2182
2183                 if (min != max) {
2184                     str = "at least " + str + " and at most " + times(max);
2185                 }
2186
2187                 return str;
2188             }
2189
2190             if (typeof min == "number") {
2191                 return "at least " + times(min);
2192             }
2193
2194             return "at most " + times(max);
2195         }
2196
2197         function receivedMinCalls(expectation) {
2198             var hasMinLimit = typeof expectation.minCalls == "number";
2199             return !hasMinLimit || expectation.callCount >= expectation.minCalls;
2200         }
2201
2202         function receivedMaxCalls(expectation) {
2203             if (typeof expectation.maxCalls != "number") {
2204                 return false;
2205             }
2206
2207             return expectation.callCount == expectation.maxCalls;
2208         }
2209
2210         return {
2211             minCalls: 1,
2212             maxCalls: 1,
2213
2214             create: function create(methodName) {
2215                 var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
2216                 delete expectation.create;
2217                 expectation.method = methodName;
2218
2219                 return expectation;
2220             },
2221
2222             invoke: function invoke(func, thisValue, args) {
2223                 this.verifyCallAllowed(thisValue, args);
2224
2225                 return _invoke.apply(this, arguments);
2226             },
2227
2228             atLeast: function atLeast(num) {
2229                 if (typeof num != "number") {
2230                     throw new TypeError("'" + num + "' is not number");
2231                 }
2232
2233                 if (!this.limitsSet) {
2234                     this.maxCalls = null;
2235                     this.limitsSet = true;
2236                 }
2237
2238                 this.minCalls = num;
2239
2240                 return this;
2241             },
2242
2243             atMost: function atMost(num) {
2244                 if (typeof num != "number") {
2245                     throw new TypeError("'" + num + "' is not number");
2246                 }
2247
2248                 if (!this.limitsSet) {
2249                     this.minCalls = null;
2250                     this.limitsSet = true;
2251                 }
2252
2253                 this.maxCalls = num;
2254
2255                 return this;
2256             },
2257
2258             never: function never() {
2259                 return this.exactly(0);
2260             },
2261
2262             once: function once() {
2263                 return this.exactly(1);
2264             },
2265
2266             twice: function twice() {
2267                 return this.exactly(2);
2268             },
2269
2270             thrice: function thrice() {
2271                 return this.exactly(3);
2272             },
2273
2274             exactly: function exactly(num) {
2275                 if (typeof num != "number") {
2276                     throw new TypeError("'" + num + "' is not a number");
2277                 }
2278
2279                 this.atLeast(num);
2280                 return this.atMost(num);
2281             },
2282
2283             met: function met() {
2284                 return !this.failed && receivedMinCalls(this);
2285             },
2286
2287             verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
2288                 if (receivedMaxCalls(this)) {
2289                     this.failed = true;
2290                     sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
2291                 }
2292
2293                 if ("expectedThis" in this && this.expectedThis !== thisValue) {
2294                     sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
2295                         this.expectedThis);
2296                 }
2297
2298                 if (!("expectedArguments" in this)) {
2299                     return;
2300                 }
2301
2302                 if (!args) {
2303                     sinon.expectation.fail(this.method + " received no arguments, expected " +
2304                         sinon.format(this.expectedArguments));
2305                 }
2306
2307                 if (args.length < this.expectedArguments.length) {
2308                     sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
2309                         "), expected " + sinon.format(this.expectedArguments));
2310                 }
2311
2312                 if (this.expectsExactArgCount &&
2313                     args.length != this.expectedArguments.length) {
2314                     sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
2315                         "), expected " + sinon.format(this.expectedArguments));
2316                 }
2317
2318                 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2319                     if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
2320                         sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
2321                             ", expected " + sinon.format(this.expectedArguments));
2322                     }
2323                 }
2324             },
2325
2326             allowsCall: function allowsCall(thisValue, args) {
2327                 if (this.met() && receivedMaxCalls(this)) {
2328                     return false;
2329                 }
2330
2331                 if ("expectedThis" in this && this.expectedThis !== thisValue) {
2332                     return false;
2333                 }
2334
2335                 if (!("expectedArguments" in this)) {
2336                     return true;
2337                 }
2338
2339                 args = args || [];
2340
2341                 if (args.length < this.expectedArguments.length) {
2342                     return false;
2343                 }
2344
2345                 if (this.expectsExactArgCount &&
2346                     args.length != this.expectedArguments.length) {
2347                     return false;
2348                 }
2349
2350                 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2351                     if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
2352                         return false;
2353                     }
2354                 }
2355
2356                 return true;
2357             },
2358
2359             withArgs: function withArgs() {
2360                 this.expectedArguments = slice.call(arguments);
2361                 return this;
2362             },
2363
2364             withExactArgs: function withExactArgs() {
2365                 this.withArgs.apply(this, arguments);
2366                 this.expectsExactArgCount = true;
2367                 return this;
2368             },
2369
2370             on: function on(thisValue) {
2371                 this.expectedThis = thisValue;
2372                 return this;
2373             },
2374
2375             toString: function () {
2376                 var args = (this.expectedArguments || []).slice();
2377
2378                 if (!this.expectsExactArgCount) {
2379                     push.call(args, "[...]");
2380                 }
2381
2382                 var callStr = sinon.spyCall.toString.call({
2383                     proxy: this.method || "anonymous mock expectation",
2384                     args: args
2385                 });
2386
2387                 var message = callStr.replace(", [...", "[, ...") + " " +
2388                     expectedCallCountInWords(this);
2389
2390                 if (this.met()) {
2391                     return "Expectation met: " + message;
2392                 }
2393
2394                 return "Expected " + message + " (" +
2395                     callCountInWords(this.callCount) + ")";
2396             },
2397
2398             verify: function verify() {
2399                 if (!this.met()) {
2400                     sinon.expectation.fail(this.toString());
2401                 } else {
2402                     sinon.expectation.pass(this.toString());
2403                 }
2404
2405                 return true;
2406             },
2407
2408             pass: function(message) {
2409               sinon.assert.pass(message);
2410             },
2411             fail: function (message) {
2412                 var exception = new Error(message);
2413                 exception.name = "ExpectationError";
2414
2415                 throw exception;
2416             }
2417         };
2418     }());
2419
2420     if (commonJSModule) {
2421         module.exports = mock;
2422     } else {
2423         sinon.mock = mock;
2424     }
2425 }(typeof sinon == "object" && sinon || null));
2426
2427 /**
2428  * @depend ../sinon.js
2429  * @depend stub.js
2430  * @depend mock.js
2431  */
2432 /*jslint eqeqeq: false, onevar: false, forin: true*/
2433 /*global module, require, sinon*/
2434 /**
2435  * Collections of stubs, spies and mocks.
2436  *
2437  * @author Christian Johansen (christian@cjohansen.no)
2438  * @license BSD
2439  *
2440  * Copyright (c) 2010-2013 Christian Johansen
2441  */
2442
2443 (function (sinon) {
2444     var commonJSModule = typeof module == "object" && typeof require == "function";
2445     var push = [].push;
2446     var hasOwnProperty = Object.prototype.hasOwnProperty;
2447
2448     if (!sinon && commonJSModule) {
2449         sinon = require("../sinon");
2450     }
2451
2452     if (!sinon) {
2453         return;
2454     }
2455
2456     function getFakes(fakeCollection) {
2457         if (!fakeCollection.fakes) {
2458             fakeCollection.fakes = [];
2459         }
2460
2461         return fakeCollection.fakes;
2462     }
2463
2464     function each(fakeCollection, method) {
2465         var fakes = getFakes(fakeCollection);
2466
2467         for (var i = 0, l = fakes.length; i < l; i += 1) {
2468             if (typeof fakes[i][method] == "function") {
2469                 fakes[i][method]();
2470             }
2471         }
2472     }
2473
2474     function compact(fakeCollection) {
2475         var fakes = getFakes(fakeCollection);
2476         var i = 0;
2477         while (i < fakes.length) {
2478           fakes.splice(i, 1);
2479         }
2480     }
2481
2482     var collection = {
2483         verify: function resolve() {
2484             each(this, "verify");
2485         },
2486
2487         restore: function restore() {
2488             each(this, "restore");
2489             compact(this);
2490         },
2491
2492         verifyAndRestore: function verifyAndRestore() {
2493             var exception;
2494
2495             try {
2496                 this.verify();
2497             } catch (e) {
2498                 exception = e;
2499             }
2500
2501             this.restore();
2502
2503             if (exception) {
2504                 throw exception;
2505             }
2506         },
2507
2508         add: function add(fake) {
2509             push.call(getFakes(this), fake);
2510             return fake;
2511         },
2512
2513         spy: function spy() {
2514             return this.add(sinon.spy.apply(sinon, arguments));
2515         },
2516
2517         stub: function stub(object, property, value) {
2518             if (property) {
2519                 var original = object[property];
2520
2521                 if (typeof original != "function") {
2522                     if (!hasOwnProperty.call(object, property)) {
2523                         throw new TypeError("Cannot stub non-existent own property " + property);
2524                     }
2525
2526                     object[property] = value;
2527
2528                     return this.add({
2529                         restore: function () {
2530                             object[property] = original;
2531                         }
2532                     });
2533                 }
2534             }
2535             if (!property && !!object && typeof object == "object") {
2536                 var stubbedObj = sinon.stub.apply(sinon, arguments);
2537
2538                 for (var prop in stubbedObj) {
2539                     if (typeof stubbedObj[prop] === "function") {
2540                         this.add(stubbedObj[prop]);
2541                     }
2542                 }
2543
2544                 return stubbedObj;
2545             }
2546
2547             return this.add(sinon.stub.apply(sinon, arguments));
2548         },
2549
2550         mock: function mock() {
2551             return this.add(sinon.mock.apply(sinon, arguments));
2552         },
2553
2554         inject: function inject(obj) {
2555             var col = this;
2556
2557             obj.spy = function () {
2558                 return col.spy.apply(col, arguments);
2559             };
2560
2561             obj.stub = function () {
2562                 return col.stub.apply(col, arguments);
2563             };
2564
2565             obj.mock = function () {
2566                 return col.mock.apply(col, arguments);
2567             };
2568
2569             return obj;
2570         }
2571     };
2572
2573     if (commonJSModule) {
2574         module.exports = collection;
2575     } else {
2576         sinon.collection = collection;
2577     }
2578 }(typeof sinon == "object" && sinon || null));
2579
2580 /*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
2581 /*global module, require, window*/
2582 /**
2583  * Fake timer API
2584  * setTimeout
2585  * setInterval
2586  * clearTimeout
2587  * clearInterval
2588  * tick
2589  * reset
2590  * Date
2591  *
2592  * Inspired by jsUnitMockTimeOut from JsUnit
2593  *
2594  * @author Christian Johansen (christian@cjohansen.no)
2595  * @license BSD
2596  *
2597  * Copyright (c) 2010-2013 Christian Johansen
2598  */
2599
2600 if (typeof sinon == "undefined") {
2601     var sinon = {};
2602 }
2603
2604 (function (global) {
2605     var id = 1;
2606
2607     function addTimer(args, recurring) {
2608         if (args.length === 0) {
2609             throw new Error("Function requires at least 1 parameter");
2610         }
2611
2612         var toId = id++;
2613         var delay = args[1] || 0;
2614
2615         if (!this.timeouts) {
2616             this.timeouts = {};
2617         }
2618
2619         this.timeouts[toId] = {
2620             id: toId,
2621             func: args[0],
2622             callAt: this.now + delay,
2623             invokeArgs: Array.prototype.slice.call(args, 2)
2624         };
2625
2626         if (recurring === true) {
2627             this.timeouts[toId].interval = delay;
2628         }
2629
2630         return toId;
2631     }
2632
2633     function parseTime(str) {
2634         if (!str) {
2635             return 0;
2636         }
2637
2638         var strings = str.split(":");
2639         var l = strings.length, i = l;
2640         var ms = 0, parsed;
2641
2642         if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
2643             throw new Error("tick only understands numbers and 'h:m:s'");
2644         }
2645
2646         while (i--) {
2647             parsed = parseInt(strings[i], 10);
2648
2649             if (parsed >= 60) {
2650                 throw new Error("Invalid time " + str);
2651             }
2652
2653             ms += parsed * Math.pow(60, (l - i - 1));
2654         }
2655
2656         return ms * 1000;
2657     }
2658
2659     function createObject(object) {
2660         var newObject;
2661
2662         if (Object.create) {
2663             newObject = Object.create(object);
2664         } else {
2665             var F = function () {};
2666             F.prototype = object;
2667             newObject = new F();
2668         }
2669
2670         newObject.Date.clock = newObject;
2671         return newObject;
2672     }
2673
2674     sinon.clock = {
2675         now: 0,
2676
2677         create: function create(now) {
2678             var clock = createObject(this);
2679
2680             if (typeof now == "number") {
2681                 clock.now = now;
2682             }
2683
2684             if (!!now && typeof now == "object") {
2685                 throw new TypeError("now should be milliseconds since UNIX epoch");
2686             }
2687
2688             return clock;
2689         },
2690
2691         setTimeout: function setTimeout(callback, timeout) {
2692             return addTimer.call(this, arguments, false);
2693         },
2694
2695         clearTimeout: function clearTimeout(timerId) {
2696             if (!this.timeouts) {
2697                 this.timeouts = [];
2698             }
2699
2700             if (timerId in this.timeouts) {
2701                 delete this.timeouts[timerId];
2702             }
2703         },
2704
2705         setInterval: function setInterval(callback, timeout) {
2706             return addTimer.call(this, arguments, true);
2707         },
2708
2709         clearInterval: function clearInterval(timerId) {
2710             this.clearTimeout(timerId);
2711         },
2712
2713         tick: function tick(ms) {
2714             ms = typeof ms == "number" ? ms : parseTime(ms);
2715             var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
2716             var timer = this.firstTimerInRange(tickFrom, tickTo);
2717
2718             var firstException;
2719             while (timer && tickFrom <= tickTo) {
2720                 if (this.timeouts[timer.id]) {
2721                     tickFrom = this.now = timer.callAt;
2722                     try {
2723                       this.callTimer(timer);
2724                     } catch (e) {
2725                       firstException = firstException || e;
2726                     }
2727                 }
2728
2729                 timer = this.firstTimerInRange(previous, tickTo);
2730                 previous = tickFrom;
2731             }
2732
2733             this.now = tickTo;
2734
2735             if (firstException) {
2736               throw firstException;
2737             }
2738
2739             return this.now;
2740         },
2741
2742         firstTimerInRange: function (from, to) {
2743             var timer, smallest, originalTimer;
2744
2745             for (var id in this.timeouts) {
2746                 if (this.timeouts.hasOwnProperty(id)) {
2747                     if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
2748                         continue;
2749                     }
2750
2751                     if (!smallest || this.timeouts[id].callAt < smallest) {
2752                         originalTimer = this.timeouts[id];
2753                         smallest = this.timeouts[id].callAt;
2754
2755                         timer = {
2756                             func: this.timeouts[id].func,
2757                             callAt: this.timeouts[id].callAt,
2758                             interval: this.timeouts[id].interval,
2759                             id: this.timeouts[id].id,
2760                             invokeArgs: this.timeouts[id].invokeArgs
2761                         };
2762                     }
2763                 }
2764             }
2765
2766             return timer || null;
2767         },
2768
2769         callTimer: function (timer) {
2770             if (typeof timer.interval == "number") {
2771                 this.timeouts[timer.id].callAt += timer.interval;
2772             } else {
2773                 delete this.timeouts[timer.id];
2774             }
2775
2776             try {
2777                 if (typeof timer.func == "function") {
2778                     timer.func.apply(null, timer.invokeArgs);
2779                 } else {
2780                     eval(timer.func);
2781                 }
2782             } catch (e) {
2783               var exception = e;
2784             }
2785
2786             if (!this.timeouts[timer.id]) {
2787                 if (exception) {
2788                   throw exception;
2789                 }
2790                 return;
2791             }
2792
2793             if (exception) {
2794               throw exception;
2795             }
2796         },
2797
2798         reset: function reset() {
2799             this.timeouts = {};
2800         },
2801
2802         Date: (function () {
2803             var NativeDate = Date;
2804
2805             function ClockDate(year, month, date, hour, minute, second, ms) {
2806                 // Defensive and verbose to avoid potential harm in passing
2807                 // explicit undefined when user does not pass argument
2808                 switch (arguments.length) {
2809                 case 0:
2810                     return new NativeDate(ClockDate.clock.now);
2811                 case 1:
2812                     return new NativeDate(year);
2813                 case 2:
2814                     return new NativeDate(year, month);
2815                 case 3:
2816                     return new NativeDate(year, month, date);
2817                 case 4:
2818                     return new NativeDate(year, month, date, hour);
2819                 case 5:
2820                     return new NativeDate(year, month, date, hour, minute);
2821                 case 6:
2822                     return new NativeDate(year, month, date, hour, minute, second);
2823                 default:
2824                     return new NativeDate(year, month, date, hour, minute, second, ms);
2825                 }
2826             }
2827
2828             return mirrorDateProperties(ClockDate, NativeDate);
2829         }())
2830     };
2831
2832     function mirrorDateProperties(target, source) {
2833         if (source.now) {
2834             target.now = function now() {
2835                 return target.clock.now;
2836             };
2837         } else {
2838             delete target.now;
2839         }
2840
2841         if (source.toSource) {
2842             target.toSource = function toSource() {
2843                 return source.toSource();
2844             };
2845         } else {
2846             delete target.toSource;
2847         }
2848
2849         target.toString = function toString() {
2850             return source.toString();
2851         };
2852
2853         target.prototype = source.prototype;
2854         target.parse = source.parse;
2855         target.UTC = source.UTC;
2856         target.prototype.toUTCString = source.prototype.toUTCString;
2857         return target;
2858     }
2859
2860     var methods = ["Date", "setTimeout", "setInterval",
2861                    "clearTimeout", "clearInterval"];
2862
2863     function restore() {
2864         var method;
2865
2866         for (var i = 0, l = this.methods.length; i < l; i++) {
2867             method = this.methods[i];
2868             if (global[method].hadOwnProperty) {
2869                 global[method] = this["_" + method];
2870             } else {
2871                 delete global[method];
2872             }
2873         }
2874
2875         // Prevent multiple executions which will completely remove these props
2876         this.methods = [];
2877     }
2878
2879     function stubGlobal(method, clock) {
2880         clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
2881         clock["_" + method] = global[method];
2882
2883         if (method == "Date") {
2884             var date = mirrorDateProperties(clock[method], global[method]);
2885             global[method] = date;
2886         } else {
2887             global[method] = function () {
2888                 return clock[method].apply(clock, arguments);
2889             };
2890
2891             for (var prop in clock[method]) {
2892                 if (clock[method].hasOwnProperty(prop)) {
2893                     global[method][prop] = clock[method][prop];
2894                 }
2895             }
2896         }
2897
2898         global[method].clock = clock;
2899     }
2900
2901     sinon.useFakeTimers = function useFakeTimers(now) {
2902         var clock = sinon.clock.create(now);
2903         clock.restore = restore;
2904         clock.methods = Array.prototype.slice.call(arguments,
2905                                                    typeof now == "number" ? 1 : 0);
2906
2907         if (clock.methods.length === 0) {
2908             clock.methods = methods;
2909         }
2910
2911         for (var i = 0, l = clock.methods.length; i < l; i++) {
2912             stubGlobal(clock.methods[i], clock);
2913         }
2914
2915         return clock;
2916     };
2917 }(typeof global != "undefined" && typeof global !== "function" ? global : this));
2918
2919 sinon.timers = {
2920     setTimeout: setTimeout,
2921     clearTimeout: clearTimeout,
2922     setInterval: setInterval,
2923     clearInterval: clearInterval,
2924     Date: Date
2925 };
2926
2927 if (typeof module == "object" && typeof require == "function") {
2928     module.exports = sinon;
2929 }
2930
2931 /*jslint eqeqeq: false, onevar: false*/
2932 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
2933 /**
2934  * Minimal Event interface implementation
2935  *
2936  * Original implementation by Sven Fuchs: https://gist.github.com/995028
2937  * Modifications and tests by Christian Johansen.
2938  *
2939  * @author Sven Fuchs (svenfuchs@artweb-design.de)
2940  * @author Christian Johansen (christian@cjohansen.no)
2941  * @license BSD
2942  *
2943  * Copyright (c) 2011 Sven Fuchs, Christian Johansen
2944  */
2945
2946 if (typeof sinon == "undefined") {
2947     this.sinon = {};
2948 }
2949
2950 (function () {
2951     var push = [].push;
2952
2953     sinon.Event = function Event(type, bubbles, cancelable, target) {
2954         this.initEvent(type, bubbles, cancelable, target);
2955     };
2956
2957     sinon.Event.prototype = {
2958         initEvent: function(type, bubbles, cancelable, target) {
2959             this.type = type;
2960             this.bubbles = bubbles;
2961             this.cancelable = cancelable;
2962             this.target = target;
2963         },
2964
2965         stopPropagation: function () {},
2966
2967         preventDefault: function () {
2968             this.defaultPrevented = true;
2969         }
2970     };
2971
2972     sinon.EventTarget = {
2973         addEventListener: function addEventListener(event, listener, useCapture) {
2974             this.eventListeners = this.eventListeners || {};
2975             this.eventListeners[event] = this.eventListeners[event] || [];
2976             push.call(this.eventListeners[event], listener);
2977         },
2978
2979         removeEventListener: function removeEventListener(event, listener, useCapture) {
2980             var listeners = this.eventListeners && this.eventListeners[event] || [];
2981
2982             for (var i = 0, l = listeners.length; i < l; ++i) {
2983                 if (listeners[i] == listener) {
2984                     return listeners.splice(i, 1);
2985                 }
2986             }
2987         },
2988
2989         dispatchEvent: function dispatchEvent(event) {
2990             var type = event.type;
2991             var listeners = this.eventListeners && this.eventListeners[type] || [];
2992
2993             for (var i = 0; i < listeners.length; i++) {
2994                 if (typeof listeners[i] == "function") {
2995                     listeners[i].call(this, event);
2996                 } else {
2997                     listeners[i].handleEvent(event);
2998                 }
2999             }
3000
3001             return !!event.defaultPrevented;
3002         }
3003     };
3004 }());
3005
3006 /**
3007  * @depend ../../sinon.js
3008  * @depend event.js
3009  */
3010 /*jslint eqeqeq: false, onevar: false*/
3011 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
3012 /**
3013  * Fake XMLHttpRequest object
3014  *
3015  * @author Christian Johansen (christian@cjohansen.no)
3016  * @license BSD
3017  *
3018  * Copyright (c) 2010-2013 Christian Johansen
3019  */
3020
3021 if (typeof sinon == "undefined") {
3022     this.sinon = {};
3023 }
3024 sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
3025
3026 // wrapper for global
3027 (function(global) {
3028     var xhr = sinon.xhr;
3029     xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
3030     xhr.GlobalActiveXObject = global.ActiveXObject;
3031     xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
3032     xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
3033     xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
3034                                      ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
3035
3036     /*jsl:ignore*/
3037     var unsafeHeaders = {
3038         "Accept-Charset": true,
3039         "Accept-Encoding": true,
3040         "Connection": true,
3041         "Content-Length": true,
3042         "Cookie": true,
3043         "Cookie2": true,
3044         "Content-Transfer-Encoding": true,
3045         "Date": true,
3046         "Expect": true,
3047         "Host": true,
3048         "Keep-Alive": true,
3049         "Referer": true,
3050         "TE": true,
3051         "Trailer": true,
3052         "Transfer-Encoding": true,
3053         "Upgrade": true,
3054         "User-Agent": true,
3055         "Via": true
3056     };
3057     /*jsl:end*/
3058
3059     function FakeXMLHttpRequest() {
3060         this.readyState = FakeXMLHttpRequest.UNSENT;
3061         this.requestHeaders = {};
3062         this.requestBody = null;
3063         this.status = 0;
3064         this.statusText = "";
3065
3066         var xhr = this;
3067         var events = ["loadstart", "load", "abort", "loadend"];
3068
3069         function addEventListener(eventName) {
3070             xhr.addEventListener(eventName, function (event) {
3071                 var listener = xhr["on" + eventName];
3072
3073                 if (listener && typeof listener == "function") {
3074                     listener(event);
3075                 }
3076             });
3077         }
3078
3079         for (var i = events.length - 1; i >= 0; i--) {
3080             addEventListener(events[i]);
3081         }
3082
3083         if (typeof FakeXMLHttpRequest.onCreate == "function") {
3084             FakeXMLHttpRequest.onCreate(this);
3085         }
3086     }
3087
3088     function verifyState(xhr) {
3089         if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
3090             throw new Error("INVALID_STATE_ERR");
3091         }
3092
3093         if (xhr.sendFlag) {
3094             throw new Error("INVALID_STATE_ERR");
3095         }
3096     }
3097
3098     // filtering to enable a white-list version of Sinon FakeXhr,
3099     // where whitelisted requests are passed through to real XHR
3100     function each(collection, callback) {
3101         if (!collection) return;
3102         for (var i = 0, l = collection.length; i < l; i += 1) {
3103             callback(collection[i]);
3104         }
3105     }
3106     function some(collection, callback) {
3107         for (var index = 0; index < collection.length; index++) {
3108             if(callback(collection[index]) === true) return true;
3109         };
3110         return false;
3111     }
3112     // largest arity in XHR is 5 - XHR#open
3113     var apply = function(obj,method,args) {
3114         switch(args.length) {
3115         case 0: return obj[method]();
3116         case 1: return obj[method](args[0]);
3117         case 2: return obj[method](args[0],args[1]);
3118         case 3: return obj[method](args[0],args[1],args[2]);
3119         case 4: return obj[method](args[0],args[1],args[2],args[3]);
3120         case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
3121         };
3122     };
3123
3124     FakeXMLHttpRequest.filters = [];
3125     FakeXMLHttpRequest.addFilter = function(fn) {
3126         this.filters.push(fn)
3127     };
3128     var IE6Re = /MSIE 6/;
3129     FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
3130         var xhr = new sinon.xhr.workingXHR();
3131         each(["open","setRequestHeader","send","abort","getResponseHeader",
3132               "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
3133              function(method) {
3134                  fakeXhr[method] = function() {
3135                    return apply(xhr,method,arguments);
3136                  };
3137              });
3138
3139         var copyAttrs = function(args) {
3140             each(args, function(attr) {
3141               try {
3142                 fakeXhr[attr] = xhr[attr]
3143               } catch(e) {
3144                 if(!IE6Re.test(navigator.userAgent)) throw e;
3145               }
3146             });
3147         };
3148
3149         var stateChange = function() {
3150             fakeXhr.readyState = xhr.readyState;
3151             if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
3152                 copyAttrs(["status","statusText"]);
3153             }
3154             if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
3155                 copyAttrs(["responseText"]);
3156             }
3157             if(xhr.readyState === FakeXMLHttpRequest.DONE) {
3158                 copyAttrs(["responseXML"]);
3159             }
3160             if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr);
3161         };
3162         if(xhr.addEventListener) {
3163           for(var event in fakeXhr.eventListeners) {
3164               if(fakeXhr.eventListeners.hasOwnProperty(event)) {
3165                   each(fakeXhr.eventListeners[event],function(handler) {
3166                       xhr.addEventListener(event, handler);
3167                   });
3168               }
3169           }
3170           xhr.addEventListener("readystatechange",stateChange);
3171         } else {
3172           xhr.onreadystatechange = stateChange;
3173         }
3174         apply(xhr,"open",xhrArgs);
3175     };
3176     FakeXMLHttpRequest.useFilters = false;
3177
3178     function verifyRequestSent(xhr) {
3179         if (xhr.readyState == FakeXMLHttpRequest.DONE) {
3180             throw new Error("Request done");
3181         }
3182     }
3183
3184     function verifyHeadersReceived(xhr) {
3185         if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
3186             throw new Error("No headers received");
3187         }
3188     }
3189
3190     function verifyResponseBodyType(body) {
3191         if (typeof body != "string") {
3192             var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
3193                                  body + ", which is not a string.");
3194             error.name = "InvalidBodyException";
3195             throw error;
3196         }
3197     }
3198
3199     sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
3200         async: true,
3201
3202         open: function open(method, url, async, username, password) {
3203             this.method = method;
3204             this.url = url;
3205             this.async = typeof async == "boolean" ? async : true;
3206             this.username = username;
3207             this.password = password;
3208             this.responseText = null;
3209             this.responseXML = null;
3210             this.requestHeaders = {};
3211             this.sendFlag = false;
3212             if(sinon.FakeXMLHttpRequest.useFilters === true) {
3213                 var xhrArgs = arguments;
3214                 var defake = some(FakeXMLHttpRequest.filters,function(filter) {
3215                     return filter.apply(this,xhrArgs)
3216                 });
3217                 if (defake) {
3218                   return sinon.FakeXMLHttpRequest.defake(this,arguments);
3219                 }
3220             }
3221             this.readyStateChange(FakeXMLHttpRequest.OPENED);
3222         },
3223
3224         readyStateChange: function readyStateChange(state) {
3225             this.readyState = state;
3226
3227             if (typeof this.onreadystatechange == "function") {
3228                 try {
3229                     this.onreadystatechange();
3230                 } catch (e) {
3231                     sinon.logError("Fake XHR onreadystatechange handler", e);
3232                 }
3233             }
3234
3235             this.dispatchEvent(new sinon.Event("readystatechange"));
3236
3237             switch (this.readyState) {
3238                 case FakeXMLHttpRequest.DONE:
3239                     this.dispatchEvent(new sinon.Event("load", false, false, this));
3240                     this.dispatchEvent(new sinon.Event("loadend", false, false, this));
3241                     break;
3242             }
3243         },
3244
3245         setRequestHeader: function setRequestHeader(header, value) {
3246             verifyState(this);
3247
3248             if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
3249                 throw new Error("Refused to set unsafe header \"" + header + "\"");
3250             }
3251
3252             if (this.requestHeaders[header]) {
3253                 this.requestHeaders[header] += "," + value;
3254             } else {
3255                 this.requestHeaders[header] = value;
3256             }
3257         },
3258
3259         // Helps testing
3260         setResponseHeaders: function setResponseHeaders(headers) {
3261             this.responseHeaders = {};
3262
3263             for (var header in headers) {
3264                 if (headers.hasOwnProperty(header)) {
3265                     this.responseHeaders[header] = headers[header];
3266                 }
3267             }
3268
3269             if (this.async) {
3270                 this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
3271             } else {
3272                 this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
3273             }
3274         },
3275
3276         // Currently treats ALL data as a DOMString (i.e. no Document)
3277         send: function send(data) {
3278             verifyState(this);
3279
3280             if (!/^(get|head)$/i.test(this.method)) {
3281                 if (this.requestHeaders["Content-Type"]) {
3282                     var value = this.requestHeaders["Content-Type"].split(";");
3283                     this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
3284                 } else {
3285                     this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
3286                 }
3287
3288                 this.requestBody = data;
3289             }
3290
3291             this.errorFlag = false;
3292             this.sendFlag = this.async;
3293             this.readyStateChange(FakeXMLHttpRequest.OPENED);
3294
3295             if (typeof this.onSend == "function") {
3296                 this.onSend(this);
3297             }
3298
3299             this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
3300         },
3301
3302         abort: function abort() {
3303             this.aborted = true;
3304             this.responseText = null;
3305             this.errorFlag = true;
3306             this.requestHeaders = {};
3307
3308             if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
3309                 this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
3310                 this.sendFlag = false;
3311             }
3312
3313             this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
3314
3315             this.dispatchEvent(new sinon.Event("abort", false, false, this));
3316             if (typeof this.onerror === "function") {
3317                 this.onerror();
3318             }
3319         },
3320
3321         getResponseHeader: function getResponseHeader(header) {
3322             if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
3323                 return null;
3324             }
3325
3326             if (/^Set-Cookie2?$/i.test(header)) {
3327                 return null;
3328             }
3329
3330             header = header.toLowerCase();
3331
3332             for (var h in this.responseHeaders) {
3333                 if (h.toLowerCase() == header) {
3334                     return this.responseHeaders[h];
3335                 }
3336             }
3337
3338             return null;
3339         },
3340
3341         getAllResponseHeaders: function getAllResponseHeaders() {
3342             if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
3343                 return "";
3344             }
3345
3346             var headers = "";
3347
3348             for (var header in this.responseHeaders) {
3349                 if (this.responseHeaders.hasOwnProperty(header) &&
3350                     !/^Set-Cookie2?$/i.test(header)) {
3351                     headers += header + ": " + this.responseHeaders[header] + "\r\n";
3352                 }
3353             }
3354
3355             return headers;
3356         },
3357
3358         setResponseBody: function setResponseBody(body) {
3359             verifyRequestSent(this);
3360             verifyHeadersReceived(this);
3361             verifyResponseBodyType(body);
3362
3363             var chunkSize = this.chunkSize || 10;
3364             var index = 0;
3365             this.responseText = "";
3366
3367             do {
3368                 if (this.async) {
3369                     this.readyStateChange(FakeXMLHttpRequest.LOADING);
3370                 }
3371
3372                 this.responseText += body.substring(index, index + chunkSize);
3373                 index += chunkSize;
3374             } while (index < body.length);
3375
3376             var type = this.getResponseHeader("Content-Type");
3377
3378             if (this.responseText &&
3379                 (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
3380                 try {
3381                     this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
3382                 } catch (e) {
3383                     // Unable to parse XML - no biggie
3384                 }
3385             }
3386
3387             if (this.async) {
3388                 this.readyStateChange(FakeXMLHttpRequest.DONE);
3389             } else {
3390                 this.readyState = FakeXMLHttpRequest.DONE;
3391             }
3392         },
3393
3394         respond: function respond(status, headers, body) {
3395             this.setResponseHeaders(headers || {});
3396             this.status = typeof status == "number" ? status : 200;
3397             this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
3398             this.setResponseBody(body || "");
3399             if (typeof this.onload === "function"){
3400                 this.onload();
3401             }
3402
3403         }
3404     });
3405
3406     sinon.extend(FakeXMLHttpRequest, {
3407         UNSENT: 0,
3408         OPENED: 1,
3409         HEADERS_RECEIVED: 2,
3410         LOADING: 3,
3411         DONE: 4
3412     });
3413
3414     // Borrowed from JSpec
3415     FakeXMLHttpRequest.parseXML = function parseXML(text) {
3416         var xmlDoc;
3417
3418         if (typeof DOMParser != "undefined") {
3419             var parser = new DOMParser();
3420             xmlDoc = parser.parseFromString(text, "text/xml");
3421         } else {
3422             xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
3423             xmlDoc.async = "false";
3424             xmlDoc.loadXML(text);
3425         }
3426
3427         return xmlDoc;
3428     };
3429
3430     FakeXMLHttpRequest.statusCodes = {
3431         100: "Continue",
3432         101: "Switching Protocols",
3433         200: "OK",
3434         201: "Created",
3435         202: "Accepted",
3436         203: "Non-Authoritative Information",
3437         204: "No Content",
3438         205: "Reset Content",
3439         206: "Partial Content",
3440         300: "Multiple Choice",
3441         301: "Moved Permanently",
3442         302: "Found",
3443         303: "See Other",
3444         304: "Not Modified",
3445         305: "Use Proxy",
3446         307: "Temporary Redirect",
3447         400: "Bad Request",
3448         401: "Unauthorized",
3449         402: "Payment Required",
3450         403: "Forbidden",
3451         404: "Not Found",
3452         405: "Method Not Allowed",
3453         406: "Not Acceptable",
3454         407: "Proxy Authentication Required",
3455         408: "Request Timeout",
3456         409: "Conflict",
3457         410: "Gone",
3458         411: "Length Required",
3459         412: "Precondition Failed",
3460         413: "Request Entity Too Large",
3461         414: "Request-URI Too Long",
3462         415: "Unsupported Media Type",
3463         416: "Requested Range Not Satisfiable",
3464         417: "Expectation Failed",
3465         422: "Unprocessable Entity",
3466         500: "Internal Server Error",
3467         501: "Not Implemented",
3468         502: "Bad Gateway",
3469         503: "Service Unavailable",
3470         504: "Gateway Timeout",
3471         505: "HTTP Version Not Supported"
3472     };
3473
3474     sinon.useFakeXMLHttpRequest = function () {
3475         sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
3476             if (xhr.supportsXHR) {
3477                 global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
3478             }
3479
3480             if (xhr.supportsActiveX) {
3481                 global.ActiveXObject = xhr.GlobalActiveXObject;
3482             }
3483
3484             delete sinon.FakeXMLHttpRequest.restore;
3485
3486             if (keepOnCreate !== true) {
3487                 delete sinon.FakeXMLHttpRequest.onCreate;
3488             }
3489         };
3490         if (xhr.supportsXHR) {
3491             global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
3492         }
3493
3494         if (xhr.supportsActiveX) {
3495             global.ActiveXObject = function ActiveXObject(objId) {
3496                 if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
3497
3498                     return new sinon.FakeXMLHttpRequest();
3499                 }
3500
3501                 return new xhr.GlobalActiveXObject(objId);
3502             };
3503         }
3504
3505         return sinon.FakeXMLHttpRequest;
3506     };
3507
3508     sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
3509 })(this);
3510
3511 if (typeof module == "object" && typeof require == "function") {
3512     module.exports = sinon;
3513 }
3514
3515 /**
3516  * @depend fake_xml_http_request.js
3517  */
3518 /*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
3519 /*global module, require, window*/
3520 /**
3521  * The Sinon "server" mimics a web server that receives requests from
3522  * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
3523  * both synchronously and asynchronously. To respond synchronuously, canned
3524  * answers have to be provided upfront.
3525  *
3526  * @author Christian Johansen (christian@cjohansen.no)
3527  * @license BSD
3528  *
3529  * Copyright (c) 2010-2013 Christian Johansen
3530  */
3531
3532 if (typeof sinon == "undefined") {
3533     var sinon = {};
3534 }
3535
3536 sinon.fakeServer = (function () {
3537     var push = [].push;
3538     function F() {}
3539
3540     function create(proto) {
3541         F.prototype = proto;
3542         return new F();
3543     }
3544
3545     function responseArray(handler) {
3546         var response = handler;
3547
3548         if (Object.prototype.toString.call(handler) != "[object Array]") {
3549             response = [200, {}, handler];
3550         }
3551
3552         if (typeof response[2] != "string") {
3553             throw new TypeError("Fake server response body should be string, but was " +
3554                                 typeof response[2]);
3555         }
3556
3557         return response;
3558     }
3559
3560     var wloc = typeof window !== "undefined" ? window.location : {};
3561     var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
3562
3563     function matchOne(response, reqMethod, reqUrl) {
3564         var rmeth = response.method;
3565         var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
3566         var url = response.url;
3567         var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
3568
3569         return matchMethod && matchUrl;
3570     }
3571
3572     function match(response, request) {
3573         var requestMethod = this.getHTTPMethod(request);
3574         var requestUrl = request.url;
3575
3576         if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
3577             requestUrl = requestUrl.replace(rCurrLoc, "");
3578         }
3579
3580         if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
3581             if (typeof response.response == "function") {
3582                 var ru = response.url;
3583                 var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1));
3584                 return response.response.apply(response, args);
3585             }
3586
3587             return true;
3588         }
3589
3590         return false;
3591     }
3592
3593     function log(response, request) {
3594         var str;
3595
3596         str =  "Request:\n"  + sinon.format(request)  + "\n\n";
3597         str += "Response:\n" + sinon.format(response) + "\n\n";
3598
3599         sinon.log(str);
3600     }
3601
3602     return {
3603         create: function () {
3604             var server = create(this);
3605             this.xhr = sinon.useFakeXMLHttpRequest();
3606             server.requests = [];
3607
3608             this.xhr.onCreate = function (xhrObj) {
3609                 server.addRequest(xhrObj);
3610             };
3611
3612             return server;
3613         },
3614
3615         addRequest: function addRequest(xhrObj) {
3616             var server = this;
3617             push.call(this.requests, xhrObj);
3618
3619             xhrObj.onSend = function () {
3620                 server.handleRequest(this);
3621             };
3622
3623             if (this.autoRespond && !this.responding) {
3624                 setTimeout(function () {
3625                     server.responding = false;
3626                     server.respond();
3627                 }, this.autoRespondAfter || 10);
3628
3629                 this.responding = true;
3630             }
3631         },
3632
3633         getHTTPMethod: function getHTTPMethod(request) {
3634             if (this.fakeHTTPMethods && /post/i.test(request.method)) {
3635                 var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
3636                 return !!matches ? matches[1] : request.method;
3637             }
3638
3639             return request.method;
3640         },
3641
3642         handleRequest: function handleRequest(xhr) {
3643             if (xhr.async) {
3644                 if (!this.queue) {
3645                     this.queue = [];
3646                 }
3647
3648                 push.call(this.queue, xhr);
3649             } else {
3650                 this.processRequest(xhr);
3651             }
3652         },
3653
3654         respondWith: function respondWith(method, url, body) {
3655             if (arguments.length == 1 && typeof method != "function") {
3656                 this.response = responseArray(method);
3657                 return;
3658             }
3659
3660             if (!this.responses) { this.responses = []; }
3661
3662             if (arguments.length == 1) {
3663                 body = method;
3664                 url = method = null;
3665             }
3666
3667             if (arguments.length == 2) {
3668                 body = url;
3669                 url = method;
3670                 method = null;
3671             }
3672
3673             push.call(this.responses, {
3674                 method: method,
3675                 url: url,
3676                 response: typeof body == "function" ? body : responseArray(body)
3677             });
3678         },
3679
3680         respond: function respond() {
3681             if (arguments.length > 0) this.respondWith.apply(this, arguments);
3682             var queue = this.queue || [];
3683             var request;
3684
3685             while(request = queue.shift()) {
3686                 this.processRequest(request);
3687             }
3688         },
3689
3690         processRequest: function processRequest(request) {
3691             try {
3692                 if (request.aborted) {
3693                     return;
3694                 }
3695
3696                 var response = this.response || [404, {}, ""];
3697
3698                 if (this.responses) {
3699                     for (var i = 0, l = this.responses.length; i < l; i++) {
3700                         if (match.call(this, this.responses[i], request)) {
3701                             response = this.responses[i].response;
3702                             break;
3703                         }
3704                     }
3705                 }
3706
3707                 if (request.readyState != 4) {
3708                     log(response, request);
3709
3710                     request.respond(response[0], response[1], response[2]);
3711                 }
3712             } catch (e) {
3713                 sinon.logError("Fake server request processing", e);
3714             }
3715         },
3716
3717         restore: function restore() {
3718             return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
3719         }
3720     };
3721 }());
3722
3723 if (typeof module == "object" && typeof require == "function") {
3724     module.exports = sinon;
3725 }
3726
3727 /**
3728  * @depend fake_server.js
3729  * @depend fake_timers.js
3730  */
3731 /*jslint browser: true, eqeqeq: false, onevar: false*/
3732 /*global sinon*/
3733 /**
3734  * Add-on for sinon.fakeServer that automatically handles a fake timer along with
3735  * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
3736  * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
3737  * it polls the object for completion with setInterval. Dispite the direct
3738  * motivation, there is nothing jQuery-specific in this file, so it can be used
3739  * in any environment where the ajax implementation depends on setInterval or
3740  * setTimeout.
3741  *
3742  * @author Christian Johansen (christian@cjohansen.no)
3743  * @license BSD
3744  *
3745  * Copyright (c) 2010-2013 Christian Johansen
3746  */
3747
3748 (function () {
3749     function Server() {}
3750     Server.prototype = sinon.fakeServer;
3751
3752     sinon.fakeServerWithClock = new Server();
3753
3754     sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
3755         if (xhr.async) {
3756             if (typeof setTimeout.clock == "object") {
3757                 this.clock = setTimeout.clock;
3758             } else {
3759                 this.clock = sinon.useFakeTimers();
3760                 this.resetClock = true;
3761             }
3762
3763             if (!this.longestTimeout) {
3764                 var clockSetTimeout = this.clock.setTimeout;
3765                 var clockSetInterval = this.clock.setInterval;
3766                 var server = this;
3767
3768                 this.clock.setTimeout = function (fn, timeout) {
3769                     server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
3770
3771                     return clockSetTimeout.apply(this, arguments);
3772                 };
3773
3774                 this.clock.setInterval = function (fn, timeout) {
3775                     server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
3776
3777                     return clockSetInterval.apply(this, arguments);
3778                 };
3779             }
3780         }
3781
3782         return sinon.fakeServer.addRequest.call(this, xhr);
3783     };
3784
3785     sinon.fakeServerWithClock.respond = function respond() {
3786         var returnVal = sinon.fakeServer.respond.apply(this, arguments);
3787
3788         if (this.clock) {
3789             this.clock.tick(this.longestTimeout || 0);
3790             this.longestTimeout = 0;
3791
3792             if (this.resetClock) {
3793                 this.clock.restore();
3794                 this.resetClock = false;
3795             }
3796         }
3797
3798         return returnVal;
3799     };
3800
3801     sinon.fakeServerWithClock.restore = function restore() {
3802         if (this.clock) {
3803             this.clock.restore();
3804         }
3805
3806         return sinon.fakeServer.restore.apply(this, arguments);
3807     };
3808 }());
3809
3810 /**
3811  * @depend ../sinon.js
3812  * @depend collection.js
3813  * @depend util/fake_timers.js
3814  * @depend util/fake_server_with_clock.js
3815  */
3816 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
3817 /*global require, module*/
3818 /**
3819  * Manages fake collections as well as fake utilities such as Sinon's
3820  * timers and fake XHR implementation in one convenient object.
3821  *
3822  * @author Christian Johansen (christian@cjohansen.no)
3823  * @license BSD
3824  *
3825  * Copyright (c) 2010-2013 Christian Johansen
3826  */
3827
3828 if (typeof module == "object" && typeof require == "function") {
3829     var sinon = require("../sinon");
3830     sinon.extend(sinon, require("./util/fake_timers"));
3831 }
3832
3833 (function () {
3834     var push = [].push;
3835
3836     function exposeValue(sandbox, config, key, value) {
3837         if (!value) {
3838             return;
3839         }
3840
3841         if (config.injectInto) {
3842             config.injectInto[key] = value;
3843         } else {
3844             push.call(sandbox.args, value);
3845         }
3846     }
3847
3848     function prepareSandboxFromConfig(config) {
3849         var sandbox = sinon.create(sinon.sandbox);
3850
3851         if (config.useFakeServer) {
3852             if (typeof config.useFakeServer == "object") {
3853                 sandbox.serverPrototype = config.useFakeServer;
3854             }
3855
3856             sandbox.useFakeServer();
3857         }
3858
3859         if (config.useFakeTimers) {
3860             if (typeof config.useFakeTimers == "object") {
3861                 sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
3862             } else {
3863                 sandbox.useFakeTimers();
3864             }
3865         }
3866
3867         return sandbox;
3868     }
3869
3870     sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
3871         useFakeTimers: function useFakeTimers() {
3872             this.clock = sinon.useFakeTimers.apply(sinon, arguments);
3873
3874             return this.add(this.clock);
3875         },
3876
3877         serverPrototype: sinon.fakeServer,
3878
3879         useFakeServer: function useFakeServer() {
3880             var proto = this.serverPrototype || sinon.fakeServer;
3881
3882             if (!proto || !proto.create) {
3883                 return null;
3884             }
3885
3886             this.server = proto.create();
3887             return this.add(this.server);
3888         },
3889
3890         inject: function (obj) {
3891             sinon.collection.inject.call(this, obj);
3892
3893             if (this.clock) {
3894                 obj.clock = this.clock;
3895             }
3896
3897             if (this.server) {
3898                 obj.server = this.server;
3899                 obj.requests = this.server.requests;
3900             }
3901
3902             return obj;
3903         },
3904
3905         create: function (config) {
3906             if (!config) {
3907                 return sinon.create(sinon.sandbox);
3908             }
3909
3910             var sandbox = prepareSandboxFromConfig(config);
3911             sandbox.args = sandbox.args || [];
3912             var prop, value, exposed = sandbox.inject({});
3913
3914             if (config.properties) {
3915                 for (var i = 0, l = config.properties.length; i < l; i++) {
3916                     prop = config.properties[i];
3917                     value = exposed[prop] || prop == "sandbox" && sandbox;
3918                     exposeValue(sandbox, config, prop, value);
3919                 }
3920             } else {
3921                 exposeValue(sandbox, config, "sandbox", value);
3922             }
3923
3924             return sandbox;
3925         }
3926     });
3927
3928     sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
3929
3930     if (typeof module == "object" && typeof require == "function") {
3931         module.exports = sinon.sandbox;
3932     }
3933 }());
3934
3935 /**
3936  * @depend ../sinon.js
3937  * @depend stub.js
3938  * @depend mock.js
3939  * @depend sandbox.js
3940  */
3941 /*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
3942 /*global module, require, sinon*/
3943 /**
3944  * Test function, sandboxes fakes
3945  *
3946  * @author Christian Johansen (christian@cjohansen.no)
3947  * @license BSD
3948  *
3949  * Copyright (c) 2010-2013 Christian Johansen
3950  */
3951
3952 (function (sinon) {
3953     var commonJSModule = typeof module == "object" && typeof require == "function";
3954
3955     if (!sinon && commonJSModule) {
3956         sinon = require("../sinon");
3957     }
3958
3959     if (!sinon) {
3960         return;
3961     }
3962
3963     function test(callback) {
3964         var type = typeof callback;
3965
3966         if (type != "function") {
3967             throw new TypeError("sinon.test needs to wrap a test function, got " + type);
3968         }
3969
3970         return function () {
3971             var config = sinon.getConfig(sinon.config);
3972             config.injectInto = config.injectIntoThis && this || config.injectInto;
3973             var sandbox = sinon.sandbox.create(config);
3974             var exception, result;
3975             var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
3976
3977             try {
3978                 result = callback.apply(this, args);
3979             } catch (e) {
3980                 exception = e;
3981             }
3982
3983             if (typeof exception !== "undefined") {
3984                 sandbox.restore();
3985                 throw exception;
3986             }
3987             else {
3988                 sandbox.verifyAndRestore();
3989             }
3990
3991             return result;
3992         };
3993     }
3994
3995     test.config = {
3996         injectIntoThis: true,
3997         injectInto: null,
3998         properties: ["spy", "stub", "mock", "clock", "server", "requests"],
3999         useFakeTimers: true,
4000         useFakeServer: true
4001     };
4002
4003     if (commonJSModule) {
4004         module.exports = test;
4005     } else {
4006         sinon.test = test;
4007     }
4008 }(typeof sinon == "object" && sinon || null));
4009
4010 /**
4011  * @depend ../sinon.js
4012  * @depend test.js
4013  */
4014 /*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
4015 /*global module, require, sinon*/
4016 /**
4017  * Test case, sandboxes all test functions
4018  *
4019  * @author Christian Johansen (christian@cjohansen.no)
4020  * @license BSD
4021  *
4022  * Copyright (c) 2010-2013 Christian Johansen
4023  */
4024
4025 (function (sinon) {
4026     var commonJSModule = typeof module == "object" && typeof require == "function";
4027
4028     if (!sinon && commonJSModule) {
4029         sinon = require("../sinon");
4030     }
4031
4032     if (!sinon || !Object.prototype.hasOwnProperty) {
4033         return;
4034     }
4035
4036     function createTest(property, setUp, tearDown) {
4037         return function () {
4038             if (setUp) {
4039                 setUp.apply(this, arguments);
4040             }
4041
4042             var exception, result;
4043
4044             try {
4045                 result = property.apply(this, arguments);
4046             } catch (e) {
4047                 exception = e;
4048             }
4049
4050             if (tearDown) {
4051                 tearDown.apply(this, arguments);
4052             }
4053
4054             if (exception) {
4055                 throw exception;
4056             }
4057
4058             return result;
4059         };
4060     }
4061
4062     function testCase(tests, prefix) {
4063         /*jsl:ignore*/
4064         if (!tests || typeof tests != "object") {
4065             throw new TypeError("sinon.testCase needs an object with test functions");
4066         }
4067         /*jsl:end*/
4068
4069         prefix = prefix || "test";
4070         var rPrefix = new RegExp("^" + prefix);
4071         var methods = {}, testName, property, method;
4072         var setUp = tests.setUp;
4073         var tearDown = tests.tearDown;
4074
4075         for (testName in tests) {
4076             if (tests.hasOwnProperty(testName)) {
4077                 property = tests[testName];
4078
4079                 if (/^(setUp|tearDown)$/.test(testName)) {
4080                     continue;
4081                 }
4082
4083                 if (typeof property == "function" && rPrefix.test(testName)) {
4084                     method = property;
4085
4086                     if (setUp || tearDown) {
4087                         method = createTest(property, setUp, tearDown);
4088                     }
4089
4090                     methods[testName] = sinon.test(method);
4091                 } else {
4092                     methods[testName] = tests[testName];
4093                 }
4094             }
4095         }
4096
4097         return methods;
4098     }
4099
4100     if (commonJSModule) {
4101         module.exports = testCase;
4102     } else {
4103         sinon.testCase = testCase;
4104     }
4105 }(typeof sinon == "object" && sinon || null));
4106
4107 /**
4108  * @depend ../sinon.js
4109  * @depend stub.js
4110  */
4111 /*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
4112 /*global module, require, sinon*/
4113 /**
4114  * Assertions matching the test spy retrieval interface.
4115  *
4116  * @author Christian Johansen (christian@cjohansen.no)
4117  * @license BSD
4118  *
4119  * Copyright (c) 2010-2013 Christian Johansen
4120  */
4121
4122 (function (sinon, global) {
4123     var commonJSModule = typeof module == "object" && typeof require == "function";
4124     var slice = Array.prototype.slice;
4125     var assert;
4126
4127     if (!sinon && commonJSModule) {
4128         sinon = require("../sinon");
4129     }
4130
4131     if (!sinon) {
4132         return;
4133     }
4134
4135     function verifyIsStub() {
4136         var method;
4137
4138         for (var i = 0, l = arguments.length; i < l; ++i) {
4139             method = arguments[i];
4140
4141             if (!method) {
4142                 assert.fail("fake is not a spy");
4143             }
4144
4145             if (typeof method != "function") {
4146                 assert.fail(method + " is not a function");
4147             }
4148
4149             if (typeof method.getCall != "function") {
4150                 assert.fail(method + " is not stubbed");
4151             }
4152         }
4153     }
4154
4155     function failAssertion(object, msg) {
4156         object = object || global;
4157         var failMethod = object.fail || assert.fail;
4158         failMethod.call(object, msg);
4159     }
4160
4161     function mirrorPropAsAssertion(name, method, message) {
4162         if (arguments.length == 2) {
4163             message = method;
4164             method = name;
4165         }
4166
4167         assert[name] = function (fake) {
4168             verifyIsStub(fake);
4169
4170             var args = slice.call(arguments, 1);
4171             var failed = false;
4172
4173             if (typeof method == "function") {
4174                 failed = !method(fake);
4175             } else {
4176                 failed = typeof fake[method] == "function" ?
4177                     !fake[method].apply(fake, args) : !fake[method];
4178             }
4179
4180             if (failed) {
4181                 failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
4182             } else {
4183                 assert.pass(name);
4184             }
4185         };
4186     }
4187
4188     function exposedName(prefix, prop) {
4189         return !prefix || /^fail/.test(prop) ? prop :
4190             prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
4191     };
4192
4193     assert = {
4194         failException: "AssertError",
4195
4196         fail: function fail(message) {
4197             var error = new Error(message);
4198             error.name = this.failException || assert.failException;
4199
4200             throw error;
4201         },
4202
4203         pass: function pass(assertion) {},
4204
4205         callOrder: function assertCallOrder() {
4206             verifyIsStub.apply(null, arguments);
4207             var expected = "", actual = "";
4208
4209             if (!sinon.calledInOrder(arguments)) {
4210                 try {
4211                     expected = [].join.call(arguments, ", ");
4212                     var calls = slice.call(arguments);
4213                     var i = calls.length;
4214                     while (i) {
4215                         if (!calls[--i].called) {
4216                             calls.splice(i, 1);
4217                         }
4218                     }
4219                     actual = sinon.orderByFirstCall(calls).join(", ");
4220                 } catch (e) {
4221                     // If this fails, we'll just fall back to the blank string
4222                 }
4223
4224                 failAssertion(this, "expected " + expected + " to be " +
4225                               "called in order but were called as " + actual);
4226             } else {
4227                 assert.pass("callOrder");
4228             }
4229         },
4230
4231         callCount: function assertCallCount(method, count) {
4232             verifyIsStub(method);
4233
4234             if (method.callCount != count) {
4235                 var msg = "expected %n to be called " + sinon.timesInWords(count) +
4236                     " but was called %c%C";
4237                 failAssertion(this, method.printf(msg));
4238             } else {
4239                 assert.pass("callCount");
4240             }
4241         },
4242
4243         expose: function expose(target, options) {
4244             if (!target) {
4245                 throw new TypeError("target is null or undefined");
4246             }
4247
4248             var o = options || {};
4249             var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
4250             var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
4251
4252             for (var method in this) {
4253                 if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
4254                     target[exposedName(prefix, method)] = this[method];
4255                 }
4256             }
4257
4258             return target;
4259         }
4260     };
4261
4262     mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
4263     mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
4264                           "expected %n to not have been called but was called %c%C");
4265     mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
4266     mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
4267     mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
4268     mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
4269     mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
4270     mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
4271     mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
4272     mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
4273     mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
4274     mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
4275     mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
4276     mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
4277     mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
4278     mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
4279     mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
4280     mirrorPropAsAssertion("threw", "%n did not throw exception%C");
4281     mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
4282
4283     if (commonJSModule) {
4284         module.exports = assert;
4285     } else {
4286         sinon.assert = assert;
4287     }
4288 }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
4289
4290 return sinon;}.call(typeof window != 'undefined' && window || {}));