UNPKG

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