3 * Sinon.JS 1.8.3, 2014/03/04
5 * @author Christian Johansen (christian@cjohansen.no)
6 * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
10 * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or without modification,
14 * are permitted provided that the following conditions are met:
16 * * Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * * Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * * Neither the name of Christian Johansen nor the names of his contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 /*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
39 * Helps IE run the fake timers. By defining global functions, IE allows
40 * them to be overwritten at a later point. If these are not defined like
41 * this, overwriting them will result in anything from an exception to browser
44 * If you don't require fake timers to work in IE, don't include this file.
46 * @author Christian Johansen (christian@cjohansen.no)
49 * Copyright (c) 2010-2013 Christian Johansen
51 function setTimeout() {}
52 function clearTimeout() {}
53 function setImmediate() {}
54 function clearImmediate() {}
55 function setInterval() {}
56 function clearInterval() {}
59 // Reassign the original functions. Now their writable attribute
60 // should be true. Hackish, I know, but it works.
61 setTimeout = sinon.timers.setTimeout;
62 clearTimeout = sinon.timers.clearTimeout;
63 setImmediate = sinon.timers.setImmediate;
64 clearImmediate = sinon.timers.clearImmediate;
65 setInterval = sinon.timers.setInterval;
66 clearInterval = sinon.timers.clearInterval;
67 Date = sinon.timers.Date;
71 * Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows
72 * them to be overwritten at a later point. If these are not defined like
73 * this, overwriting them will result in anything from an exception to browser
76 * If you don't require fake XHR to work in IE, don't include this file.
78 * @author Christian Johansen (christian@cjohansen.no)
81 * Copyright (c) 2010-2013 Christian Johansen
83 function XMLHttpRequest() {}
85 // Reassign the original function. Now its writable attribute
86 // should be true. Hackish, I know, but it works.
87 XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
91 * Sinon.JS 1.8.3, 2014/03/04
93 * @author Christian Johansen (christian@cjohansen.no)
94 * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
98 * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
99 * All rights reserved.
101 * Redistribution and use in source and binary forms, with or without modification,
102 * are permitted provided that the following conditions are met:
104 * * Redistributions of source code must retain the above copyright notice,
105 * this list of conditions and the following disclaimer.
106 * * Redistributions in binary form must reproduce the above copyright notice,
107 * this list of conditions and the following disclaimer in the documentation
108 * and/or other materials provided with the distribution.
109 * * Neither the name of Christian Johansen nor the names of his contributors
110 * may be used to endorse or promote products derived from this software
111 * without specific prior written permission.
113 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
114 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
115 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
116 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
117 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
118 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
119 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
120 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
121 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
122 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
125 this.sinon = (function () {
126 var samsam, formatio;
127 function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else { formatio = fn(samsam); } }
129 ((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
130 (typeof module === "object" &&
131 function (m) { module.exports = m(); }) || // Node
132 function (m) { this.samsam = m(); } // Browser globals
134 var o = Object.prototype;
135 var div = typeof document !== "undefined" && document.createElement("div");
137 function isNaN(value) {
138 // Unlike global isNaN, this avoids type coercion
139 // typeof check avoids IE host object issues, hat tip to
141 var val = value; // JsLint thinks value !== value is "weird"
142 return typeof value === "number" && value !== val;
145 function getClass(value) {
146 // Returns the internal [[Class]] by calling Object.prototype.toString
147 // with the provided value as this. Return value is a string, naming the
148 // internal class, e.g. "Array"
149 return o.toString.call(value).split(/[ \]]/)[1];
153 * @name samsam.isArguments
154 * @param Object object
156 * Returns ``true`` if ``object`` is an ``arguments`` object,
157 * ``false`` otherwise.
159 function isArguments(object) {
160 if (typeof object !== "object" || typeof object.length !== "number" ||
161 getClass(object) === "Array") {
164 if (typeof object.callee == "function") { return true; }
166 object[object.length] = 6;
167 delete object[object.length];
175 * @name samsam.isElement
176 * @param Object object
178 * Returns ``true`` if ``object`` is a DOM element node. Unlike
179 * Underscore.js/lodash, this function will return ``false`` if ``object``
180 * is an *element-like* object, i.e. a regular object with a ``nodeType``
181 * property that holds the value ``1``.
183 function isElement(object) {
184 if (!object || object.nodeType !== 1 || !div) { return false; }
186 object.appendChild(div);
187 object.removeChild(div);
196 * @param Object object
198 * Return an array of own property names.
200 function keys(object) {
202 for (prop in object) {
203 if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
209 * @name samsam.isDate
210 * @param Object value
212 * Returns true if the object is a ``Date``, or *date-like*. Duck typing
213 * of date objects work by checking that the object has a ``getTime``
214 * function whose return value equals the return value from the object's
217 function isDate(value) {
218 return typeof value.getTime == "function" &&
219 value.getTime() == value.valueOf();
223 * @name samsam.isNegZero
224 * @param Object value
226 * Returns ``true`` if ``value`` is ``-0``.
228 function isNegZero(value) {
229 return value === 0 && 1 / value === -Infinity;
237 * Returns ``true`` if two objects are strictly equal. Compared to
238 * ``===`` there are two exceptions:
240 * - NaN is considered equal to NaN
241 * - -0 and +0 are not considered equal
243 function identical(obj1, obj2) {
244 if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
245 return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
251 * @name samsam.deepEqual
255 * Deep equal comparison. Two values are "deep equal" if:
257 * - They are equal, according to samsam.identical
258 * - They are both date objects representing the same time
259 * - They are both arrays containing elements that are all deepEqual
260 * - They are objects with the same set of properties, and each property
261 * in ``obj1`` is deepEqual to the corresponding property in ``obj2``
263 * Supports cyclic objects.
265 function deepEqualCyclic(obj1, obj2) {
267 // used for cyclic comparison
268 // contain already visited objects
271 // contain pathes (position in the object structure)
272 // of the already visited objects
273 // indexes same as in objects arrays
276 // contains combinations of already compared objects
277 // in the manner: { "$1['ref']$2['ref']": true }
281 * used to check, if the value of a property is an object
282 * (cyclic logic is only needed for objects)
283 * only needed for cyclic logic
285 function isObject(value) {
287 if (typeof value === 'object' && value !== null &&
288 !(value instanceof Boolean) &&
289 !(value instanceof Date) &&
290 !(value instanceof Number) &&
291 !(value instanceof RegExp) &&
292 !(value instanceof String)) {
301 * returns the index of the given object in the
302 * given objects array, -1 if not contained
303 * only needed for cyclic logic
305 function getIndex(objects, obj) {
308 for (i = 0; i < objects.length; i++) {
309 if (objects[i] === obj) {
317 // does the recursion for the deep equal check
318 return (function deepEqual(obj1, obj2, path1, path2) {
319 var type1 = typeof obj1;
320 var type2 = typeof obj2;
322 // == null also matches undefined
324 isNaN(obj1) || isNaN(obj2) ||
325 obj1 == null || obj2 == null ||
326 type1 !== "object" || type2 !== "object") {
328 return identical(obj1, obj2);
331 // Elements are only equal if identical(expected, actual)
332 if (isElement(obj1) || isElement(obj2)) { return false; }
334 var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
335 if (isDate1 || isDate2) {
336 if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
341 if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
342 if (obj1.toString() !== obj2.toString()) { return false; }
345 var class1 = getClass(obj1);
346 var class2 = getClass(obj2);
347 var keys1 = keys(obj1);
348 var keys2 = keys(obj2);
350 if (isArguments(obj1) || isArguments(obj2)) {
351 if (obj1.length !== obj2.length) { return false; }
353 if (type1 !== type2 || class1 !== class2 ||
354 keys1.length !== keys2.length) {
360 // following vars are used for the cyclic logic
362 isObject1, isObject2,
366 for (i = 0, l = keys1.length; i < l; i++) {
368 if (!o.hasOwnProperty.call(obj2, key)) {
372 // Start of the cyclic logic
377 isObject1 = isObject(value1);
378 isObject2 = isObject(value2);
380 // determine, if the objects were already visited
381 // (it's faster to check for isObject first, than to
382 // get -1 from getIndex for non objects)
383 index1 = isObject1 ? getIndex(objects1, value1) : -1;
384 index2 = isObject2 ? getIndex(objects2, value2) : -1;
386 // determine the new pathes of the objects
387 // - for non cyclic objects the current path will be extended
388 // by current property name
389 // - for cyclic objects the stored path is taken
390 newPath1 = index1 !== -1
392 : path1 + '[' + JSON.stringify(key) + ']';
393 newPath2 = index2 !== -1
395 : path2 + '[' + JSON.stringify(key) + ']';
397 // stop recursion if current objects are already compared
398 if (compared[newPath1 + newPath2]) {
402 // remember the current objects and their pathes
403 if (index1 === -1 && isObject1) {
404 objects1.push(value1);
405 paths1.push(newPath1);
407 if (index2 === -1 && isObject2) {
408 objects2.push(value2);
409 paths2.push(newPath2);
412 // remember that the current objects are already compared
413 if (isObject1 && isObject2) {
414 compared[newPath1 + newPath2] = true;
417 // End of cyclic logic
419 // neither value1 nor value2 is a cycle
420 // continue with next level
421 if (!deepEqual(value1, value2, newPath1, newPath2)) {
428 }(obj1, obj2, '$1', '$2'));
433 function arrayContains(array, subset) {
434 if (subset.length === 0) { return true; }
436 for (i = 0, l = array.length; i < l; ++i) {
437 if (match(array[i], subset[0])) {
438 for (j = 0, k = subset.length; j < k; ++j) {
439 if (!match(array[i + j], subset[j])) { return false; }
449 * @param Object object
450 * @param Object matcher
452 * Compare arbitrary value ``object`` with matcher.
454 match = function match(object, matcher) {
455 if (matcher && typeof matcher.test === "function") {
456 return matcher.test(object);
459 if (typeof matcher === "function") {
460 return matcher(object) === true;
463 if (typeof matcher === "string") {
464 matcher = matcher.toLowerCase();
465 var notNull = typeof object === "string" || !!object;
467 (String(object)).toLowerCase().indexOf(matcher) >= 0;
470 if (typeof matcher === "number") {
471 return matcher === object;
474 if (typeof matcher === "boolean") {
475 return matcher === object;
478 if (getClass(object) === "Array" && getClass(matcher) === "Array") {
479 return arrayContains(object, matcher);
482 if (matcher && typeof matcher === "object") {
484 for (prop in matcher) {
485 if (!match(object[prop], matcher[prop])) {
492 throw new Error("Matcher was not a string, a number, a " +
493 "function, a boolean or an object");
497 isArguments: isArguments,
498 isElement: isElement,
500 isNegZero: isNegZero,
501 identical: identical,
502 deepEqual: deepEqualCyclic,
507 ((typeof define === "function" && define.amd && function (m) {
508 define("formatio", ["samsam"], m);
509 }) || (typeof module === "object" && function (m) {
510 module.exports = m(require("samsam"));
511 }) || function (m) { this.formatio = m(this.samsam); }
512 )(function (samsam) {
515 excludeConstructors: ["Object", /^.$/],
519 var hasOwn = Object.prototype.hasOwnProperty;
521 var specialObjects = [];
522 if (typeof global !== "undefined") {
523 specialObjects.push({ object: global, value: "[object global]" });
525 if (typeof document !== "undefined") {
526 specialObjects.push({
528 value: "[object HTMLDocument]"
531 if (typeof window !== "undefined") {
532 specialObjects.push({ object: window, value: "[object Window]" });
535 function functionName(func) {
536 if (!func) { return ""; }
537 if (func.displayName) { return func.displayName; }
538 if (func.name) { return func.name; }
539 var matches = func.toString().match(/function\s+([^\(]+)/m);
540 return (matches && matches[1]) || "";
543 function constructorName(f, object) {
544 var name = functionName(object && object.constructor);
545 var excludes = f.excludeConstructors ||
546 formatio.excludeConstructors || [];
549 for (i = 0, l = excludes.length; i < l; ++i) {
550 if (typeof excludes[i] === "string" && excludes[i] === name) {
552 } else if (excludes[i].test && excludes[i].test(name)) {
560 function isCircular(object, objects) {
561 if (typeof object !== "object") { return false; }
563 for (i = 0, l = objects.length; i < l; ++i) {
564 if (objects[i] === object) { return true; }
569 function ascii(f, object, processed, indent) {
570 if (typeof object === "string") {
571 var qs = f.quoteStrings;
572 var quote = typeof qs !== "boolean" || qs;
573 return processed || quote ? '"' + object + '"' : object;
576 if (typeof object === "function" && !(object instanceof RegExp)) {
577 return ascii.func(object);
580 processed = processed || [];
582 if (isCircular(object, processed)) { return "[Circular]"; }
584 if (Object.prototype.toString.call(object) === "[object Array]") {
585 return ascii.array.call(f, object, processed);
588 if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
589 if (samsam.isElement(object)) { return ascii.element(object); }
591 if (typeof object.toString === "function" &&
592 object.toString !== Object.prototype.toString) {
593 return object.toString();
597 for (i = 0, l = specialObjects.length; i < l; i++) {
598 if (object === specialObjects[i].object) {
599 return specialObjects[i].value;
603 return ascii.object.call(f, object, processed, indent);
606 ascii.func = function (func) {
607 return "function " + functionName(func) + "() {}";
610 ascii.array = function (array, processed) {
611 processed = processed || [];
612 processed.push(array);
613 var i, l, pieces = [];
614 for (i = 0, l = array.length; i < l; ++i) {
615 pieces.push(ascii(this, array[i], processed));
617 return "[" + pieces.join(", ") + "]";
620 ascii.object = function (object, processed, indent) {
621 processed = processed || [];
622 processed.push(object);
623 indent = indent || 0;
624 var pieces = [], properties = samsam.keys(object).sort();
626 var prop, str, obj, i, l;
628 for (i = 0, l = properties.length; i < l; ++i) {
629 prop = properties[i];
632 if (isCircular(obj, processed)) {
635 str = ascii(this, obj, processed, indent + 2);
638 str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
639 length += str.length;
643 var cons = constructorName(this, object);
644 var prefix = cons ? "[" + cons + "] " : "";
646 for (i = 0, l = indent; i < l; ++i) { is += " "; }
648 if (length + indent > 80) {
649 return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" +
652 return prefix + "{ " + pieces.join(", ") + " }";
655 ascii.element = function (element) {
656 var tagName = element.tagName.toLowerCase();
657 var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
659 for (i = 0, l = attrs.length; i < l; ++i) {
660 attr = attrs.item(i);
661 attrName = attr.nodeName.toLowerCase().replace("html:", "");
662 val = attr.nodeValue;
663 if (attrName !== "contenteditable" || val !== "inherit") {
664 if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
668 var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
669 var content = element.innerHTML;
671 if (content.length > 20) {
672 content = content.substr(0, 20) + "[...]";
675 var res = formatted + pairs.join(" ") + ">" + content +
676 "</" + tagName + ">";
678 return res.replace(/ contentEditable="inherit"/, "");
681 function Formatio(options) {
682 for (var opt in options) {
683 this[opt] = options[opt];
687 Formatio.prototype = {
688 functionName: functionName,
690 configure: function (options) {
691 return new Formatio(options);
694 constructorName: function (object) {
695 return constructorName(this, object);
698 ascii: function (object, processed, indent) {
699 return ascii(this, object, processed, indent);
703 return Formatio.prototype;
705 /*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
706 /*global module, require, __dirname, document*/
708 * Sinon core utilities. For internal use only.
710 * @author Christian Johansen (christian@cjohansen.no)
713 * Copyright (c) 2010-2013 Christian Johansen
716 var sinon = (function (formatio) {
717 var div = typeof document != "undefined" && document.createElement("div");
718 var hasOwn = Object.prototype.hasOwnProperty;
720 function isDOMNode(obj) {
724 obj.appendChild(div);
725 success = div.parentNode == obj;
730 obj.removeChild(div);
732 // Remove failed, not much we can do about that
739 function isElement(obj) {
740 return div && obj && obj.nodeType === 1 && isDOMNode(obj);
743 function isFunction(obj) {
744 return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
747 function mirrorProperties(target, source) {
748 for (var prop in source) {
749 if (!hasOwn.call(target, prop)) {
750 target[prop] = source[prop];
755 function isRestorable (obj) {
756 return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
760 wrapMethod: function wrapMethod(object, property, method) {
762 throw new TypeError("Should wrap property of object");
765 if (typeof method != "function") {
766 throw new TypeError("Method wrapper should be function");
769 var wrappedMethod = object[property],
772 if (!isFunction(wrappedMethod)) {
773 error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
774 property + " as function");
777 if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
778 error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
781 if (wrappedMethod.calledBefore) {
782 var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
783 error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
787 if (wrappedMethod._stack) {
788 error.stack += '\n--------------\n' + wrappedMethod._stack;
793 // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
794 // when using hasOwn.call on objects from other frames.
795 var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
796 object[property] = method;
797 method.displayName = property;
798 // Set up a stack trace which can be used later to find what line of
799 // code the original method was created on.
800 method._stack = (new Error('Stack Trace for original')).stack;
802 method.restore = function () {
803 // For prototype properties try to reset by delete first.
804 // If this fails (ex: localStorage on mobile safari) then force a reset
805 // via direct assignment.
807 delete object[property];
809 if (object[property] === method) {
810 object[property] = wrappedMethod;
814 method.restore.sinon = true;
815 mirrorProperties(method, wrappedMethod);
820 extend: function extend(target) {
821 for (var i = 1, l = arguments.length; i < l; i += 1) {
822 for (var prop in arguments[i]) {
823 if (arguments[i].hasOwnProperty(prop)) {
824 target[prop] = arguments[i][prop];
827 // DONT ENUM bug, only care about toString
828 if (arguments[i].hasOwnProperty("toString") &&
829 arguments[i].toString != target.toString) {
830 target.toString = arguments[i].toString;
838 create: function create(proto) {
839 var F = function () {};
844 deepEqual: function deepEqual(a, b) {
845 if (sinon.match && sinon.match.isMatcher(a)) {
848 if (typeof a != "object" || typeof b != "object") {
852 if (isElement(a) || isElement(b)) {
860 if ((a === null && b !== null) || (a !== null && b === null)) {
864 if (a instanceof RegExp && b instanceof RegExp) {
865 return (a.source === b.source) && (a.global === b.global) &&
866 (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
869 var aString = Object.prototype.toString.call(a);
870 if (aString != Object.prototype.toString.call(b)) {
874 if (aString == "[object Date]") {
875 return a.valueOf() === b.valueOf();
878 var prop, aLength = 0, bLength = 0;
880 if (aString == "[object Array]" && a.length !== b.length) {
887 if (!deepEqual(a[prop], b[prop])) {
896 return aLength == bLength;
899 functionName: function functionName(func) {
900 var name = func.displayName || func.name;
902 // Use function decomposition as a last resort to get function
903 // name. Does not rely on function decomposition to work - if it
904 // doesn't debugging will be slightly less informative
905 // (i.e. toString will say 'spy' rather than 'myFunc').
907 var matches = func.toString().match(/function ([^\s\(]+)/);
908 name = matches && matches[1];
914 functionToString: function toString() {
915 if (this.getCall && this.callCount) {
916 var thisValue, prop, i = this.callCount;
919 thisValue = this.getCall(i).thisValue;
921 for (prop in thisValue) {
922 if (thisValue[prop] === this) {
929 return this.displayName || "sinon fake";
932 getConfig: function (custom) {
934 custom = custom || {};
935 var defaults = sinon.defaultConfig;
937 for (var prop in defaults) {
938 if (defaults.hasOwnProperty(prop)) {
939 config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
946 format: function (val) {
951 injectIntoThis: true,
953 properties: ["spy", "stub", "mock", "clock", "server", "requests"],
958 timesInWords: function timesInWords(count) {
959 return count == 1 && "once" ||
960 count == 2 && "twice" ||
961 count == 3 && "thrice" ||
962 (count || 0) + " times";
965 calledInOrder: function (spies) {
966 for (var i = 1, l = spies.length; i < l; i++) {
967 if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
975 orderByFirstCall: function (spies) {
976 return spies.sort(function (a, b) {
977 // uuid, won't ever be equal
978 var aCall = a.getCall(0);
979 var bCall = b.getCall(0);
980 var aId = aCall && aCall.callId || -1;
981 var bId = bCall && bCall.callId || -1;
983 return aId < bId ? -1 : 1;
989 logError: function (label, err) {
990 var msg = label + " threw exception: ";
991 sinon.log(msg + "[" + err.name + "] " + err.message);
992 if (err.stack) { sinon.log(err.stack); }
994 setTimeout(function () {
995 err.message = msg + err.message;
1000 typeOf: function (value) {
1001 if (value === null) {
1004 else if (value === undefined) {
1007 var string = Object.prototype.toString.call(value);
1008 return string.substring(8, string.length - 1).toLowerCase();
1011 createStubInstance: function (constructor) {
1012 if (typeof constructor !== "function") {
1013 throw new TypeError("The constructor should be a function.");
1015 return sinon.stub(sinon.create(constructor.prototype));
1018 restore: function (object) {
1019 if (object !== null && typeof object === "object") {
1020 for (var prop in object) {
1021 if (isRestorable(object[prop])) {
1022 object[prop].restore();
1026 else if (isRestorable(object)) {
1032 var isNode = typeof module !== "undefined" && module.exports;
1033 var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
1039 } else if (isNode) {
1041 formatio = require("formatio");
1043 module.exports = sinon;
1044 module.exports.spy = require("./sinon/spy");
1045 module.exports.spyCall = require("./sinon/call");
1046 module.exports.behavior = require("./sinon/behavior");
1047 module.exports.stub = require("./sinon/stub");
1048 module.exports.mock = require("./sinon/mock");
1049 module.exports.collection = require("./sinon/collection");
1050 module.exports.assert = require("./sinon/assert");
1051 module.exports.sandbox = require("./sinon/sandbox");
1052 module.exports.test = require("./sinon/test");
1053 module.exports.testCase = require("./sinon/test_case");
1054 module.exports.assert = require("./sinon/assert");
1055 module.exports.match = require("./sinon/match");
1059 var formatter = formatio.configure({ quoteStrings: false });
1060 sinon.format = function () {
1061 return formatter.ascii.apply(formatter, arguments);
1063 } else if (isNode) {
1065 var util = require("util");
1066 sinon.format = function (value) {
1067 return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
1070 /* Node, but no util module - would be very old, but better safe than
1076 }(typeof formatio == "object" && formatio));
1078 /* @depend ../sinon.js */
1079 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
1080 /*global module, require, sinon*/
1084 * @author Maximilian Antoni (mail@maxantoni.de)
1087 * Copyright (c) 2012 Maximilian Antoni
1091 var commonJSModule = typeof module !== 'undefined' && module.exports;
1093 if (!sinon && commonJSModule) {
1094 sinon = require("../sinon");
1101 function assertType(value, type, name) {
1102 var actual = sinon.typeOf(value);
1103 if (actual !== type) {
1104 throw new TypeError("Expected type of " + name + " to be " +
1105 type + ", but was " + actual);
1110 toString: function () {
1111 return this.message;
1115 function isMatcher(object) {
1116 return matcher.isPrototypeOf(object);
1119 function matchObject(expectation, actual) {
1120 if (actual === null || actual === undefined) {
1123 for (var key in expectation) {
1124 if (expectation.hasOwnProperty(key)) {
1125 var exp = expectation[key];
1126 var act = actual[key];
1127 if (match.isMatcher(exp)) {
1128 if (!exp.test(act)) {
1131 } else if (sinon.typeOf(exp) === "object") {
1132 if (!matchObject(exp, act)) {
1135 } else if (!sinon.deepEqual(exp, act)) {
1143 matcher.or = function (m2) {
1144 if (!arguments.length) {
1145 throw new TypeError("Matcher expected");
1146 } else if (!isMatcher(m2)) {
1150 var or = sinon.create(matcher);
1151 or.test = function (actual) {
1152 return m1.test(actual) || m2.test(actual);
1154 or.message = m1.message + ".or(" + m2.message + ")";
1158 matcher.and = function (m2) {
1159 if (!arguments.length) {
1160 throw new TypeError("Matcher expected");
1161 } else if (!isMatcher(m2)) {
1165 var and = sinon.create(matcher);
1166 and.test = function (actual) {
1167 return m1.test(actual) && m2.test(actual);
1169 and.message = m1.message + ".and(" + m2.message + ")";
1173 var match = function (expectation, message) {
1174 var m = sinon.create(matcher);
1175 var type = sinon.typeOf(expectation);
1178 if (typeof expectation.test === "function") {
1179 m.test = function (actual) {
1180 return expectation.test(actual) === true;
1182 m.message = "match(" + sinon.functionName(expectation.test) + ")";
1186 for (var key in expectation) {
1187 if (expectation.hasOwnProperty(key)) {
1188 str.push(key + ": " + expectation[key]);
1191 m.test = function (actual) {
1192 return matchObject(expectation, actual);
1194 m.message = "match(" + str.join(", ") + ")";
1197 m.test = function (actual) {
1198 return expectation == actual;
1202 m.test = function (actual) {
1203 if (typeof actual !== "string") {
1206 return actual.indexOf(expectation) !== -1;
1208 m.message = "match(\"" + expectation + "\")";
1211 m.test = function (actual) {
1212 if (typeof actual !== "string") {
1215 return expectation.test(actual);
1219 m.test = expectation;
1221 m.message = message;
1223 m.message = "match(" + sinon.functionName(expectation) + ")";
1227 m.test = function (actual) {
1228 return sinon.deepEqual(expectation, actual);
1232 m.message = "match(" + expectation + ")";
1237 match.isMatcher = isMatcher;
1239 match.any = match(function () {
1243 match.defined = match(function (actual) {
1244 return actual !== null && actual !== undefined;
1247 match.truthy = match(function (actual) {
1251 match.falsy = match(function (actual) {
1255 match.same = function (expectation) {
1256 return match(function (actual) {
1257 return expectation === actual;
1258 }, "same(" + expectation + ")");
1261 match.typeOf = function (type) {
1262 assertType(type, "string", "type");
1263 return match(function (actual) {
1264 return sinon.typeOf(actual) === type;
1265 }, "typeOf(\"" + type + "\")");
1268 match.instanceOf = function (type) {
1269 assertType(type, "function", "type");
1270 return match(function (actual) {
1271 return actual instanceof type;
1272 }, "instanceOf(" + sinon.functionName(type) + ")");
1275 function createPropertyMatcher(propertyTest, messagePrefix) {
1276 return function (property, value) {
1277 assertType(property, "string", "property");
1278 var onlyProperty = arguments.length === 1;
1279 var message = messagePrefix + "(\"" + property + "\"";
1280 if (!onlyProperty) {
1281 message += ", " + value;
1284 return match(function (actual) {
1285 if (actual === undefined || actual === null ||
1286 !propertyTest(actual, property)) {
1289 return onlyProperty || sinon.deepEqual(value, actual[property]);
1294 match.has = createPropertyMatcher(function (actual, property) {
1295 if (typeof actual === "object") {
1296 return property in actual;
1298 return actual[property] !== undefined;
1301 match.hasOwn = createPropertyMatcher(function (actual, property) {
1302 return actual.hasOwnProperty(property);
1305 match.bool = match.typeOf("boolean");
1306 match.number = match.typeOf("number");
1307 match.string = match.typeOf("string");
1308 match.object = match.typeOf("object");
1309 match.func = match.typeOf("function");
1310 match.array = match.typeOf("array");
1311 match.regexp = match.typeOf("regexp");
1312 match.date = match.typeOf("date");
1314 if (commonJSModule) {
1315 module.exports = match;
1317 sinon.match = match;
1319 }(typeof sinon == "object" && sinon || null));
1322 * @depend ../sinon.js
1325 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
1326 /*global module, require, sinon*/
1330 * @author Christian Johansen (christian@cjohansen.no)
1331 * @author Maximilian Antoni (mail@maxantoni.de)
1334 * Copyright (c) 2010-2013 Christian Johansen
1335 * Copyright (c) 2013 Maximilian Antoni
1339 var commonJSModule = typeof module !== 'undefined' && module.exports;
1340 if (!sinon && commonJSModule) {
1341 sinon = require("../sinon");
1348 function throwYieldError(proxy, text, args) {
1349 var msg = sinon.functionName(proxy) + text;
1351 msg += " Received [" + slice.call(args).join(", ") + "]";
1353 throw new Error(msg);
1356 var slice = Array.prototype.slice;
1359 calledOn: function calledOn(thisValue) {
1360 if (sinon.match && sinon.match.isMatcher(thisValue)) {
1361 return thisValue.test(this.thisValue);
1363 return this.thisValue === thisValue;
1366 calledWith: function calledWith() {
1367 for (var i = 0, l = arguments.length; i < l; i += 1) {
1368 if (!sinon.deepEqual(arguments[i], this.args[i])) {
1376 calledWithMatch: function calledWithMatch() {
1377 for (var i = 0, l = arguments.length; i < l; i += 1) {
1378 var actual = this.args[i];
1379 var expectation = arguments[i];
1380 if (!sinon.match || !sinon.match(expectation).test(actual)) {
1387 calledWithExactly: function calledWithExactly() {
1388 return arguments.length == this.args.length &&
1389 this.calledWith.apply(this, arguments);
1392 notCalledWith: function notCalledWith() {
1393 return !this.calledWith.apply(this, arguments);
1396 notCalledWithMatch: function notCalledWithMatch() {
1397 return !this.calledWithMatch.apply(this, arguments);
1400 returned: function returned(value) {
1401 return sinon.deepEqual(value, this.returnValue);
1404 threw: function threw(error) {
1405 if (typeof error === "undefined" || !this.exception) {
1406 return !!this.exception;
1409 return this.exception === error || this.exception.name === error;
1412 calledWithNew: function calledWithNew() {
1413 return this.proxy.prototype && this.thisValue instanceof this.proxy;
1416 calledBefore: function (other) {
1417 return this.callId < other.callId;
1420 calledAfter: function (other) {
1421 return this.callId > other.callId;
1424 callArg: function (pos) {
1428 callArgOn: function (pos, thisValue) {
1429 this.args[pos].apply(thisValue);
1432 callArgWith: function (pos) {
1433 this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
1436 callArgOnWith: function (pos, thisValue) {
1437 var args = slice.call(arguments, 2);
1438 this.args[pos].apply(thisValue, args);
1441 "yield": function () {
1442 this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
1445 yieldOn: function (thisValue) {
1446 var args = this.args;
1447 for (var i = 0, l = args.length; i < l; ++i) {
1448 if (typeof args[i] === "function") {
1449 args[i].apply(thisValue, slice.call(arguments, 1));
1453 throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
1456 yieldTo: function (prop) {
1457 this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
1460 yieldToOn: function (prop, thisValue) {
1461 var args = this.args;
1462 for (var i = 0, l = args.length; i < l; ++i) {
1463 if (args[i] && typeof args[i][prop] === "function") {
1464 args[i][prop].apply(thisValue, slice.call(arguments, 2));
1468 throwYieldError(this.proxy, " cannot yield to '" + prop +
1469 "' since no callback was passed.", args);
1472 toString: function () {
1473 var callStr = this.proxy.toString() + "(";
1476 for (var i = 0, l = this.args.length; i < l; ++i) {
1477 args.push(sinon.format(this.args[i]));
1480 callStr = callStr + args.join(", ") + ")";
1482 if (typeof this.returnValue != "undefined") {
1483 callStr += " => " + sinon.format(this.returnValue);
1486 if (this.exception) {
1487 callStr += " !" + this.exception.name;
1489 if (this.exception.message) {
1490 callStr += "(" + this.exception.message + ")";
1498 callProto.invokeCallback = callProto.yield;
1500 function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
1501 if (typeof id !== "number") {
1502 throw new TypeError("Call id is not a number");
1504 var proxyCall = sinon.create(callProto);
1505 proxyCall.proxy = spy;
1506 proxyCall.thisValue = thisValue;
1507 proxyCall.args = args;
1508 proxyCall.returnValue = returnValue;
1509 proxyCall.exception = exception;
1510 proxyCall.callId = id;
1514 createSpyCall.toString = callProto.toString; // used by mocks
1516 if (commonJSModule) {
1517 module.exports = createSpyCall;
1519 sinon.spyCall = createSpyCall;
1521 }(typeof sinon == "object" && sinon || null));
1525 * @depend ../sinon.js
1528 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
1529 /*global module, require, sinon*/
1533 * @author Christian Johansen (christian@cjohansen.no)
1536 * Copyright (c) 2010-2013 Christian Johansen
1540 var commonJSModule = typeof module !== 'undefined' && module.exports;
1541 var push = Array.prototype.push;
1542 var slice = Array.prototype.slice;
1545 if (!sinon && commonJSModule) {
1546 sinon = require("../sinon");
1553 function spy(object, property) {
1554 if (!property && typeof object == "function") {
1555 return spy.create(object);
1558 if (!object && !property) {
1559 return spy.create(function () { });
1562 var method = object[property];
1563 return sinon.wrapMethod(object, property, spy.create(method));
1566 function matchingFake(fakes, args, strict) {
1571 for (var i = 0, l = fakes.length; i < l; i++) {
1572 if (fakes[i].matches(args, strict)) {
1578 function incrementCallCount() {
1580 this.callCount += 1;
1581 this.notCalled = false;
1582 this.calledOnce = this.callCount == 1;
1583 this.calledTwice = this.callCount == 2;
1584 this.calledThrice = this.callCount == 3;
1587 function createCallProperties() {
1588 this.firstCall = this.getCall(0);
1589 this.secondCall = this.getCall(1);
1590 this.thirdCall = this.getCall(2);
1591 this.lastCall = this.getCall(this.callCount - 1);
1594 var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
1595 function createProxy(func) {
1596 // Retain the function length:
1599 eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
1600 ") { return p.invoke(func, this, slice.call(arguments)); });");
1603 p = function proxy() {
1604 return p.invoke(func, this, slice.call(arguments));
1614 reset: function () {
1615 this.called = false;
1616 this.notCalled = true;
1617 this.calledOnce = false;
1618 this.calledTwice = false;
1619 this.calledThrice = false;
1621 this.firstCall = null;
1622 this.secondCall = null;
1623 this.thirdCall = null;
1624 this.lastCall = null;
1626 this.returnValues = [];
1627 this.thisValues = [];
1628 this.exceptions = [];
1631 for (var i = 0; i < this.fakes.length; i++) {
1632 this.fakes[i].reset();
1637 create: function create(func) {
1640 if (typeof func != "function") {
1641 func = function () { };
1643 name = sinon.functionName(func);
1646 var proxy = createProxy(func);
1648 sinon.extend(proxy, spy);
1649 delete proxy.create;
1650 sinon.extend(proxy, func);
1653 proxy.prototype = func.prototype;
1654 proxy.displayName = name || "spy";
1655 proxy.toString = sinon.functionToString;
1656 proxy._create = sinon.spy.create;
1657 proxy.id = "spy#" + uuid++;
1662 invoke: function invoke(func, thisValue, args) {
1663 var matching = matchingFake(this.fakes, args);
1664 var exception, returnValue;
1666 incrementCallCount.call(this);
1667 push.call(this.thisValues, thisValue);
1668 push.call(this.args, args);
1669 push.call(this.callIds, callId++);
1673 returnValue = matching.invoke(func, thisValue, args);
1675 returnValue = (this.func || func).apply(thisValue, args);
1678 var thisCall = this.getCall(this.callCount - 1);
1679 if (thisCall.calledWithNew() && typeof returnValue !== 'object') {
1680 returnValue = thisValue;
1686 push.call(this.exceptions, exception);
1687 push.call(this.returnValues, returnValue);
1689 createCallProperties.call(this);
1691 if (exception !== undefined) {
1698 getCall: function getCall(i) {
1699 if (i < 0 || i >= this.callCount) {
1703 return sinon.spyCall(this, this.thisValues[i], this.args[i],
1704 this.returnValues[i], this.exceptions[i],
1708 getCalls: function () {
1712 for (i = 0; i < this.callCount; i++) {
1713 calls.push(this.getCall(i));
1719 calledBefore: function calledBefore(spyFn) {
1724 if (!spyFn.called) {
1728 return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
1731 calledAfter: function calledAfter(spyFn) {
1732 if (!this.called || !spyFn.called) {
1736 return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
1739 withArgs: function () {
1740 var args = slice.call(arguments);
1743 var match = matchingFake(this.fakes, args, true);
1752 var original = this;
1753 var fake = this._create();
1754 fake.matchingAguments = args;
1756 push.call(this.fakes, fake);
1758 fake.withArgs = function () {
1759 return original.withArgs.apply(original, arguments);
1762 for (var i = 0; i < this.args.length; i++) {
1763 if (fake.matches(this.args[i])) {
1764 incrementCallCount.call(fake);
1765 push.call(fake.thisValues, this.thisValues[i]);
1766 push.call(fake.args, this.args[i]);
1767 push.call(fake.returnValues, this.returnValues[i]);
1768 push.call(fake.exceptions, this.exceptions[i]);
1769 push.call(fake.callIds, this.callIds[i]);
1772 createCallProperties.call(fake);
1777 matches: function (args, strict) {
1778 var margs = this.matchingAguments;
1780 if (margs.length <= args.length &&
1781 sinon.deepEqual(margs, args.slice(0, margs.length))) {
1782 return !strict || margs.length == args.length;
1786 printf: function (format) {
1788 var args = slice.call(arguments, 1);
1791 return (format || "").replace(/%(.)/g, function (match, specifyer) {
1792 formatter = spyApi.formatters[specifyer];
1794 if (typeof formatter == "function") {
1795 return formatter.call(null, spy, args);
1796 } else if (!isNaN(parseInt(specifyer, 10))) {
1797 return sinon.format(args[specifyer - 1]);
1800 return "%" + specifyer;
1805 function delegateToCalls(method, matchAny, actual, notCalled) {
1806 spyApi[method] = function () {
1809 return notCalled.apply(this, arguments);
1817 for (var i = 0, l = this.callCount; i < l; i += 1) {
1818 currentCall = this.getCall(i);
1820 if (currentCall[actual || method].apply(currentCall, arguments)) {
1829 return matches === this.callCount;
1833 delegateToCalls("calledOn", true);
1834 delegateToCalls("alwaysCalledOn", false, "calledOn");
1835 delegateToCalls("calledWith", true);
1836 delegateToCalls("calledWithMatch", true);
1837 delegateToCalls("alwaysCalledWith", false, "calledWith");
1838 delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
1839 delegateToCalls("calledWithExactly", true);
1840 delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
1841 delegateToCalls("neverCalledWith", false, "notCalledWith",
1842 function () { return true; });
1843 delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
1844 function () { return true; });
1845 delegateToCalls("threw", true);
1846 delegateToCalls("alwaysThrew", false, "threw");
1847 delegateToCalls("returned", true);
1848 delegateToCalls("alwaysReturned", false, "returned");
1849 delegateToCalls("calledWithNew", true);
1850 delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
1851 delegateToCalls("callArg", false, "callArgWith", function () {
1852 throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
1854 spyApi.callArgWith = spyApi.callArg;
1855 delegateToCalls("callArgOn", false, "callArgOnWith", function () {
1856 throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
1858 spyApi.callArgOnWith = spyApi.callArgOn;
1859 delegateToCalls("yield", false, "yield", function () {
1860 throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
1862 // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
1863 spyApi.invokeCallback = spyApi.yield;
1864 delegateToCalls("yieldOn", false, "yieldOn", function () {
1865 throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
1867 delegateToCalls("yieldTo", false, "yieldTo", function (property) {
1868 throw new Error(this.toString() + " cannot yield to '" + property +
1869 "' since it was not yet invoked.");
1871 delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
1872 throw new Error(this.toString() + " cannot yield to '" + property +
1873 "' since it was not yet invoked.");
1876 spyApi.formatters = {
1877 "c": function (spy) {
1878 return sinon.timesInWords(spy.callCount);
1881 "n": function (spy) {
1882 return spy.toString();
1885 "C": function (spy) {
1888 for (var i = 0, l = spy.callCount; i < l; ++i) {
1889 var stringifiedCall = " " + spy.getCall(i).toString();
1890 if (/\n/.test(calls[i - 1])) {
1891 stringifiedCall = "\n" + stringifiedCall;
1893 push.call(calls, stringifiedCall);
1896 return calls.length > 0 ? "\n" + calls.join("\n") : "";
1899 "t": function (spy) {
1902 for (var i = 0, l = spy.callCount; i < l; ++i) {
1903 push.call(objects, sinon.format(spy.thisValues[i]));
1906 return objects.join(", ");
1909 "*": function (spy, args) {
1912 for (var i = 0, l = args.length; i < l; ++i) {
1913 push.call(formatted, sinon.format(args[i]));
1916 return formatted.join(", ");
1920 sinon.extend(spy, spyApi);
1922 spy.spyCall = sinon.spyCall;
1924 if (commonJSModule) {
1925 module.exports = spy;
1929 }(typeof sinon == "object" && sinon || null));
1932 * @depend ../sinon.js
1934 /*jslint eqeqeq: false, onevar: false*/
1935 /*global module, require, sinon, process, setImmediate, setTimeout*/
1939 * @author Christian Johansen (christian@cjohansen.no)
1940 * @author Tim Fischbach (mail@timfischbach.de)
1943 * Copyright (c) 2010-2013 Christian Johansen
1947 var commonJSModule = typeof module !== 'undefined' && module.exports;
1949 if (!sinon && commonJSModule) {
1950 sinon = require("../sinon");
1957 var slice = Array.prototype.slice;
1958 var join = Array.prototype.join;
1961 var nextTick = (function () {
1962 if (typeof process === "object" && typeof process.nextTick === "function") {
1963 return process.nextTick;
1964 } else if (typeof setImmediate === "function") {
1965 return setImmediate;
1967 return function (callback) {
1968 setTimeout(callback, 0);
1973 function throwsException(error, message) {
1974 if (typeof error == "string") {
1975 this.exception = new Error(message || "");
1976 this.exception.name = error;
1977 } else if (!error) {
1978 this.exception = new Error("Error");
1980 this.exception = error;
1986 function getCallback(behavior, args) {
1987 var callArgAt = behavior.callArgAt;
1989 if (callArgAt < 0) {
1990 var callArgProp = behavior.callArgProp;
1992 for (var i = 0, l = args.length; i < l; ++i) {
1993 if (!callArgProp && typeof args[i] == "function") {
1997 if (callArgProp && args[i] &&
1998 typeof args[i][callArgProp] == "function") {
1999 return args[i][callArgProp];
2006 return args[callArgAt];
2009 function getCallbackError(behavior, func, args) {
2010 if (behavior.callArgAt < 0) {
2013 if (behavior.callArgProp) {
2014 msg = sinon.functionName(behavior.stub) +
2015 " expected to yield to '" + behavior.callArgProp +
2016 "', but no object with such a property was passed.";
2018 msg = sinon.functionName(behavior.stub) +
2019 " expected to yield, but no callback was passed.";
2022 if (args.length > 0) {
2023 msg += " Received [" + join.call(args, ", ") + "]";
2029 return "argument at index " + behavior.callArgAt + " is not a function: " + func;
2032 function callCallback(behavior, args) {
2033 if (typeof behavior.callArgAt == "number") {
2034 var func = getCallback(behavior, args);
2036 if (typeof func != "function") {
2037 throw new TypeError(getCallbackError(behavior, func, args));
2040 if (behavior.callbackAsync) {
2041 nextTick(function() {
2042 func.apply(behavior.callbackContext, behavior.callbackArguments);
2045 func.apply(behavior.callbackContext, behavior.callbackArguments);
2051 create: function(stub) {
2052 var behavior = sinon.extend({}, sinon.behavior);
2053 delete behavior.create;
2054 behavior.stub = stub;
2059 isPresent: function() {
2060 return (typeof this.callArgAt == 'number' ||
2062 typeof this.returnArgAt == 'number' ||
2064 this.returnValueDefined);
2067 invoke: function(context, args) {
2068 callCallback(this, args);
2070 if (this.exception) {
2071 throw this.exception;
2072 } else if (typeof this.returnArgAt == 'number') {
2073 return args[this.returnArgAt];
2074 } else if (this.returnThis) {
2078 return this.returnValue;
2081 onCall: function(index) {
2082 return this.stub.onCall(index);
2085 onFirstCall: function() {
2086 return this.stub.onFirstCall();
2089 onSecondCall: function() {
2090 return this.stub.onSecondCall();
2093 onThirdCall: function() {
2094 return this.stub.onThirdCall();
2097 withArgs: function(/* arguments */) {
2098 throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' +
2099 'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.');
2102 callsArg: function callsArg(pos) {
2103 if (typeof pos != "number") {
2104 throw new TypeError("argument index is not number");
2107 this.callArgAt = pos;
2108 this.callbackArguments = [];
2109 this.callbackContext = undefined;
2110 this.callArgProp = undefined;
2111 this.callbackAsync = false;
2116 callsArgOn: function callsArgOn(pos, context) {
2117 if (typeof pos != "number") {
2118 throw new TypeError("argument index is not number");
2120 if (typeof context != "object") {
2121 throw new TypeError("argument context is not an object");
2124 this.callArgAt = pos;
2125 this.callbackArguments = [];
2126 this.callbackContext = context;
2127 this.callArgProp = undefined;
2128 this.callbackAsync = false;
2133 callsArgWith: function callsArgWith(pos) {
2134 if (typeof pos != "number") {
2135 throw new TypeError("argument index is not number");
2138 this.callArgAt = pos;
2139 this.callbackArguments = slice.call(arguments, 1);
2140 this.callbackContext = undefined;
2141 this.callArgProp = undefined;
2142 this.callbackAsync = false;
2147 callsArgOnWith: function callsArgWith(pos, context) {
2148 if (typeof pos != "number") {
2149 throw new TypeError("argument index is not number");
2151 if (typeof context != "object") {
2152 throw new TypeError("argument context is not an object");
2155 this.callArgAt = pos;
2156 this.callbackArguments = slice.call(arguments, 2);
2157 this.callbackContext = context;
2158 this.callArgProp = undefined;
2159 this.callbackAsync = false;
2164 yields: function () {
2165 this.callArgAt = -1;
2166 this.callbackArguments = slice.call(arguments, 0);
2167 this.callbackContext = undefined;
2168 this.callArgProp = undefined;
2169 this.callbackAsync = false;
2174 yieldsOn: function (context) {
2175 if (typeof context != "object") {
2176 throw new TypeError("argument context is not an object");
2179 this.callArgAt = -1;
2180 this.callbackArguments = slice.call(arguments, 1);
2181 this.callbackContext = context;
2182 this.callArgProp = undefined;
2183 this.callbackAsync = false;
2188 yieldsTo: function (prop) {
2189 this.callArgAt = -1;
2190 this.callbackArguments = slice.call(arguments, 1);
2191 this.callbackContext = undefined;
2192 this.callArgProp = prop;
2193 this.callbackAsync = false;
2198 yieldsToOn: function (prop, context) {
2199 if (typeof context != "object") {
2200 throw new TypeError("argument context is not an object");
2203 this.callArgAt = -1;
2204 this.callbackArguments = slice.call(arguments, 2);
2205 this.callbackContext = context;
2206 this.callArgProp = prop;
2207 this.callbackAsync = false;
2213 "throws": throwsException,
2214 throwsException: throwsException,
2216 returns: function returns(value) {
2217 this.returnValue = value;
2218 this.returnValueDefined = true;
2223 returnsArg: function returnsArg(pos) {
2224 if (typeof pos != "number") {
2225 throw new TypeError("argument index is not number");
2228 this.returnArgAt = pos;
2233 returnsThis: function returnsThis() {
2234 this.returnThis = true;
2240 // create asynchronous versions of callsArg* and yields* methods
2241 for (var method in proto) {
2242 // need to avoid creating anotherasync versions of the newly added async methods
2243 if (proto.hasOwnProperty(method) &&
2244 method.match(/^(callsArg|yields)/) &&
2245 !method.match(/Async/)) {
2246 proto[method + 'Async'] = (function (syncFnName) {
2247 return function () {
2248 var result = this[syncFnName].apply(this, arguments);
2249 this.callbackAsync = true;
2256 if (commonJSModule) {
2257 module.exports = proto;
2259 sinon.behavior = proto;
2261 }(typeof sinon == "object" && sinon || null));
2263 * @depend ../sinon.js
2265 * @depend behavior.js
2267 /*jslint eqeqeq: false, onevar: false*/
2268 /*global module, require, sinon*/
2272 * @author Christian Johansen (christian@cjohansen.no)
2275 * Copyright (c) 2010-2013 Christian Johansen
2279 var commonJSModule = typeof module !== 'undefined' && module.exports;
2281 if (!sinon && commonJSModule) {
2282 sinon = require("../sinon");
2289 function stub(object, property, func) {
2290 if (!!func && typeof func != "function") {
2291 throw new TypeError("Custom stub should be function");
2297 wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
2299 wrapper = stub.create();
2302 if (!object && typeof property === "undefined") {
2303 return sinon.stub.create();
2306 if (typeof property === "undefined" && typeof object == "object") {
2307 for (var prop in object) {
2308 if (typeof object[prop] === "function") {
2316 return sinon.wrapMethod(object, property, wrapper);
2319 function getDefaultBehavior(stub) {
2320 return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
2323 function getParentBehaviour(stub) {
2324 return (stub.parent && getCurrentBehavior(stub.parent));
2327 function getCurrentBehavior(stub) {
2328 var behavior = stub.behaviors[stub.callCount - 1];
2329 return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
2334 sinon.extend(stub, (function () {
2336 create: function create() {
2337 var functionStub = function () {
2338 return getCurrentBehavior(functionStub).invoke(this, arguments);
2341 functionStub.id = "stub#" + uuid++;
2342 var orig = functionStub;
2343 functionStub = sinon.spy.create(functionStub);
2344 functionStub.func = orig;
2346 sinon.extend(functionStub, stub);
2347 functionStub._create = sinon.stub.create;
2348 functionStub.displayName = "stub";
2349 functionStub.toString = sinon.functionToString;
2351 functionStub.defaultBehavior = null;
2352 functionStub.behaviors = [];
2354 return functionStub;
2357 resetBehavior: function () {
2360 this.defaultBehavior = null;
2361 this.behaviors = [];
2363 delete this.returnValue;
2364 delete this.returnArgAt;
2365 this.returnThis = false;
2368 for (i = 0; i < this.fakes.length; i++) {
2369 this.fakes[i].resetBehavior();
2374 onCall: function(index) {
2375 if (!this.behaviors[index]) {
2376 this.behaviors[index] = sinon.behavior.create(this);
2379 return this.behaviors[index];
2382 onFirstCall: function() {
2383 return this.onCall(0);
2386 onSecondCall: function() {
2387 return this.onCall(1);
2390 onThirdCall: function() {
2391 return this.onCall(2);
2395 for (var method in sinon.behavior) {
2396 if (sinon.behavior.hasOwnProperty(method) &&
2397 !proto.hasOwnProperty(method) &&
2398 method != 'create' &&
2399 method != 'withArgs' &&
2400 method != 'invoke') {
2401 proto[method] = (function(behaviorMethod) {
2403 this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
2404 this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
2414 if (commonJSModule) {
2415 module.exports = stub;
2419 }(typeof sinon == "object" && sinon || null));
2422 * @depend ../sinon.js
2425 /*jslint eqeqeq: false, onevar: false, nomen: false*/
2426 /*global module, require, sinon*/
2430 * @author Christian Johansen (christian@cjohansen.no)
2433 * Copyright (c) 2010-2013 Christian Johansen
2437 var commonJSModule = typeof module !== 'undefined' && module.exports;
2441 if (!sinon && commonJSModule) {
2442 sinon = require("../sinon");
2449 match = sinon.match;
2451 if (!match && commonJSModule) {
2452 match = require("./match");
2455 function mock(object) {
2457 return sinon.expectation.create("Anonymous mock");
2460 return mock.create(object);
2465 sinon.extend(mock, (function () {
2466 function each(collection, callback) {
2471 for (var i = 0, l = collection.length; i < l; i += 1) {
2472 callback(collection[i]);
2477 create: function create(object) {
2479 throw new TypeError("object is null");
2482 var mockObject = sinon.extend({}, mock);
2483 mockObject.object = object;
2484 delete mockObject.create;
2489 expects: function expects(method) {
2491 throw new TypeError("method is falsy");
2494 if (!this.expectations) {
2495 this.expectations = {};
2499 if (!this.expectations[method]) {
2500 this.expectations[method] = [];
2501 var mockObject = this;
2503 sinon.wrapMethod(this.object, method, function () {
2504 return mockObject.invokeMethod(method, this, arguments);
2507 push.call(this.proxies, method);
2510 var expectation = sinon.expectation.create(method);
2511 push.call(this.expectations[method], expectation);
2516 restore: function restore() {
2517 var object = this.object;
2519 each(this.proxies, function (proxy) {
2520 if (typeof object[proxy].restore == "function") {
2521 object[proxy].restore();
2526 verify: function verify() {
2527 var expectations = this.expectations || {};
2528 var messages = [], met = [];
2530 each(this.proxies, function (proxy) {
2531 each(expectations[proxy], function (expectation) {
2532 if (!expectation.met()) {
2533 push.call(messages, expectation.toString());
2535 push.call(met, expectation.toString());
2542 if (messages.length > 0) {
2543 sinon.expectation.fail(messages.concat(met).join("\n"));
2545 sinon.expectation.pass(messages.concat(met).join("\n"));
2551 invokeMethod: function invokeMethod(method, thisValue, args) {
2552 var expectations = this.expectations && this.expectations[method];
2553 var length = expectations && expectations.length || 0, i;
2555 for (i = 0; i < length; i += 1) {
2556 if (!expectations[i].met() &&
2557 expectations[i].allowsCall(thisValue, args)) {
2558 return expectations[i].apply(thisValue, args);
2562 var messages = [], available, exhausted = 0;
2564 for (i = 0; i < length; i += 1) {
2565 if (expectations[i].allowsCall(thisValue, args)) {
2566 available = available || expectations[i];
2570 push.call(messages, " " + expectations[i].toString());
2573 if (exhausted === 0) {
2574 return available.apply(thisValue, args);
2577 messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
2582 sinon.expectation.fail(messages.join("\n"));
2587 var times = sinon.timesInWords;
2589 sinon.expectation = (function () {
2590 var slice = Array.prototype.slice;
2591 var _invoke = sinon.spy.invoke;
2593 function callCountInWords(callCount) {
2594 if (callCount == 0) {
2595 return "never called";
2597 return "called " + times(callCount);
2601 function expectedCallCountInWords(expectation) {
2602 var min = expectation.minCalls;
2603 var max = expectation.maxCalls;
2605 if (typeof min == "number" && typeof max == "number") {
2606 var str = times(min);
2609 str = "at least " + str + " and at most " + times(max);
2615 if (typeof min == "number") {
2616 return "at least " + times(min);
2619 return "at most " + times(max);
2622 function receivedMinCalls(expectation) {
2623 var hasMinLimit = typeof expectation.minCalls == "number";
2624 return !hasMinLimit || expectation.callCount >= expectation.minCalls;
2627 function receivedMaxCalls(expectation) {
2628 if (typeof expectation.maxCalls != "number") {
2632 return expectation.callCount == expectation.maxCalls;
2635 function verifyMatcher(possibleMatcher, arg){
2636 if (match && match.isMatcher(possibleMatcher)) {
2637 return possibleMatcher.test(arg);
2647 create: function create(methodName) {
2648 var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
2649 delete expectation.create;
2650 expectation.method = methodName;
2655 invoke: function invoke(func, thisValue, args) {
2656 this.verifyCallAllowed(thisValue, args);
2658 return _invoke.apply(this, arguments);
2661 atLeast: function atLeast(num) {
2662 if (typeof num != "number") {
2663 throw new TypeError("'" + num + "' is not number");
2666 if (!this.limitsSet) {
2667 this.maxCalls = null;
2668 this.limitsSet = true;
2671 this.minCalls = num;
2676 atMost: function atMost(num) {
2677 if (typeof num != "number") {
2678 throw new TypeError("'" + num + "' is not number");
2681 if (!this.limitsSet) {
2682 this.minCalls = null;
2683 this.limitsSet = true;
2686 this.maxCalls = num;
2691 never: function never() {
2692 return this.exactly(0);
2695 once: function once() {
2696 return this.exactly(1);
2699 twice: function twice() {
2700 return this.exactly(2);
2703 thrice: function thrice() {
2704 return this.exactly(3);
2707 exactly: function exactly(num) {
2708 if (typeof num != "number") {
2709 throw new TypeError("'" + num + "' is not a number");
2713 return this.atMost(num);
2716 met: function met() {
2717 return !this.failed && receivedMinCalls(this);
2720 verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
2721 if (receivedMaxCalls(this)) {
2723 sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
2726 if ("expectedThis" in this && this.expectedThis !== thisValue) {
2727 sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
2731 if (!("expectedArguments" in this)) {
2736 sinon.expectation.fail(this.method + " received no arguments, expected " +
2737 sinon.format(this.expectedArguments));
2740 if (args.length < this.expectedArguments.length) {
2741 sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
2742 "), expected " + sinon.format(this.expectedArguments));
2745 if (this.expectsExactArgCount &&
2746 args.length != this.expectedArguments.length) {
2747 sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
2748 "), expected " + sinon.format(this.expectedArguments));
2751 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2753 if (!verifyMatcher(this.expectedArguments[i],args[i])) {
2754 sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
2755 ", didn't match " + this.expectedArguments.toString());
2758 if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
2759 sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
2760 ", expected " + sinon.format(this.expectedArguments));
2765 allowsCall: function allowsCall(thisValue, args) {
2766 if (this.met() && receivedMaxCalls(this)) {
2770 if ("expectedThis" in this && this.expectedThis !== thisValue) {
2774 if (!("expectedArguments" in this)) {
2780 if (args.length < this.expectedArguments.length) {
2784 if (this.expectsExactArgCount &&
2785 args.length != this.expectedArguments.length) {
2789 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2790 if (!verifyMatcher(this.expectedArguments[i],args[i])) {
2794 if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
2802 withArgs: function withArgs() {
2803 this.expectedArguments = slice.call(arguments);
2807 withExactArgs: function withExactArgs() {
2808 this.withArgs.apply(this, arguments);
2809 this.expectsExactArgCount = true;
2813 on: function on(thisValue) {
2814 this.expectedThis = thisValue;
2818 toString: function () {
2819 var args = (this.expectedArguments || []).slice();
2821 if (!this.expectsExactArgCount) {
2822 push.call(args, "[...]");
2825 var callStr = sinon.spyCall.toString.call({
2826 proxy: this.method || "anonymous mock expectation",
2830 var message = callStr.replace(", [...", "[, ...") + " " +
2831 expectedCallCountInWords(this);
2834 return "Expectation met: " + message;
2837 return "Expected " + message + " (" +
2838 callCountInWords(this.callCount) + ")";
2841 verify: function verify() {
2843 sinon.expectation.fail(this.toString());
2845 sinon.expectation.pass(this.toString());
2851 pass: function(message) {
2852 sinon.assert.pass(message);
2854 fail: function (message) {
2855 var exception = new Error(message);
2856 exception.name = "ExpectationError";
2863 if (commonJSModule) {
2864 module.exports = mock;
2868 }(typeof sinon == "object" && sinon || null));
2871 * @depend ../sinon.js
2875 /*jslint eqeqeq: false, onevar: false, forin: true*/
2876 /*global module, require, sinon*/
2878 * Collections of stubs, spies and mocks.
2880 * @author Christian Johansen (christian@cjohansen.no)
2883 * Copyright (c) 2010-2013 Christian Johansen
2887 var commonJSModule = typeof module !== 'undefined' && module.exports;
2889 var hasOwnProperty = Object.prototype.hasOwnProperty;
2891 if (!sinon && commonJSModule) {
2892 sinon = require("../sinon");
2899 function getFakes(fakeCollection) {
2900 if (!fakeCollection.fakes) {
2901 fakeCollection.fakes = [];
2904 return fakeCollection.fakes;
2907 function each(fakeCollection, method) {
2908 var fakes = getFakes(fakeCollection);
2910 for (var i = 0, l = fakes.length; i < l; i += 1) {
2911 if (typeof fakes[i][method] == "function") {
2917 function compact(fakeCollection) {
2918 var fakes = getFakes(fakeCollection);
2920 while (i < fakes.length) {
2926 verify: function resolve() {
2927 each(this, "verify");
2930 restore: function restore() {
2931 each(this, "restore");
2935 verifyAndRestore: function verifyAndRestore() {
2951 add: function add(fake) {
2952 push.call(getFakes(this), fake);
2956 spy: function spy() {
2957 return this.add(sinon.spy.apply(sinon, arguments));
2960 stub: function stub(object, property, value) {
2962 var original = object[property];
2964 if (typeof original != "function") {
2965 if (!hasOwnProperty.call(object, property)) {
2966 throw new TypeError("Cannot stub non-existent own property " + property);
2969 object[property] = value;
2972 restore: function () {
2973 object[property] = original;
2978 if (!property && !!object && typeof object == "object") {
2979 var stubbedObj = sinon.stub.apply(sinon, arguments);
2981 for (var prop in stubbedObj) {
2982 if (typeof stubbedObj[prop] === "function") {
2983 this.add(stubbedObj[prop]);
2990 return this.add(sinon.stub.apply(sinon, arguments));
2993 mock: function mock() {
2994 return this.add(sinon.mock.apply(sinon, arguments));
2997 inject: function inject(obj) {
3000 obj.spy = function () {
3001 return col.spy.apply(col, arguments);
3004 obj.stub = function () {
3005 return col.stub.apply(col, arguments);
3008 obj.mock = function () {
3009 return col.mock.apply(col, arguments);
3016 if (commonJSModule) {
3017 module.exports = collection;
3019 sinon.collection = collection;
3021 }(typeof sinon == "object" && sinon || null));
3023 /*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
3024 /*global module, require, window*/
3035 * Inspired by jsUnitMockTimeOut from JsUnit
3037 * @author Christian Johansen (christian@cjohansen.no)
3040 * Copyright (c) 2010-2013 Christian Johansen
3043 if (typeof sinon == "undefined") {
3047 (function (global) {
3050 function addTimer(args, recurring) {
3051 if (args.length === 0) {
3052 throw new Error("Function requires at least 1 parameter");
3055 if (typeof args[0] === "undefined") {
3056 throw new Error("Callback must be provided to timer calls");
3060 var delay = args[1] || 0;
3062 if (!this.timeouts) {
3066 this.timeouts[toId] = {
3069 callAt: this.now + delay,
3070 invokeArgs: Array.prototype.slice.call(args, 2)
3073 if (recurring === true) {
3074 this.timeouts[toId].interval = delay;
3080 function parseTime(str) {
3085 var strings = str.split(":");
3086 var l = strings.length, i = l;
3089 if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
3090 throw new Error("tick only understands numbers and 'h:m:s'");
3094 parsed = parseInt(strings[i], 10);
3097 throw new Error("Invalid time " + str);
3100 ms += parsed * Math.pow(60, (l - i - 1));
3106 function createObject(object) {
3109 if (Object.create) {
3110 newObject = Object.create(object);
3112 var F = function () {};
3113 F.prototype = object;
3114 newObject = new F();
3117 newObject.Date.clock = newObject;
3124 create: function create(now) {
3125 var clock = createObject(this);
3127 if (typeof now == "number") {
3131 if (!!now && typeof now == "object") {
3132 throw new TypeError("now should be milliseconds since UNIX epoch");
3138 setTimeout: function setTimeout(callback, timeout) {
3139 return addTimer.call(this, arguments, false);
3142 clearTimeout: function clearTimeout(timerId) {
3143 if (!this.timeouts) {
3147 if (timerId in this.timeouts) {
3148 delete this.timeouts[timerId];
3152 setInterval: function setInterval(callback, timeout) {
3153 return addTimer.call(this, arguments, true);
3156 clearInterval: function clearInterval(timerId) {
3157 this.clearTimeout(timerId);
3160 setImmediate: function setImmediate(callback) {
3161 var passThruArgs = Array.prototype.slice.call(arguments, 1);
3163 return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
3166 clearImmediate: function clearImmediate(timerId) {
3167 this.clearTimeout(timerId);
3170 tick: function tick(ms) {
3171 ms = typeof ms == "number" ? ms : parseTime(ms);
3172 var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
3173 var timer = this.firstTimerInRange(tickFrom, tickTo);
3176 while (timer && tickFrom <= tickTo) {
3177 if (this.timeouts[timer.id]) {
3178 tickFrom = this.now = timer.callAt;
3180 this.callTimer(timer);
3182 firstException = firstException || e;
3186 timer = this.firstTimerInRange(previous, tickTo);
3187 previous = tickFrom;
3192 if (firstException) {
3193 throw firstException;
3199 firstTimerInRange: function (from, to) {
3200 var timer, smallest = null, originalTimer;
3202 for (var id in this.timeouts) {
3203 if (this.timeouts.hasOwnProperty(id)) {
3204 if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
3208 if (smallest === null || this.timeouts[id].callAt < smallest) {
3209 originalTimer = this.timeouts[id];
3210 smallest = this.timeouts[id].callAt;
3213 func: this.timeouts[id].func,
3214 callAt: this.timeouts[id].callAt,
3215 interval: this.timeouts[id].interval,
3216 id: this.timeouts[id].id,
3217 invokeArgs: this.timeouts[id].invokeArgs
3223 return timer || null;
3226 callTimer: function (timer) {
3227 if (typeof timer.interval == "number") {
3228 this.timeouts[timer.id].callAt += timer.interval;
3230 delete this.timeouts[timer.id];
3234 if (typeof timer.func == "function") {
3235 timer.func.apply(null, timer.invokeArgs);
3243 if (!this.timeouts[timer.id]) {
3255 reset: function reset() {
3259 Date: (function () {
3260 var NativeDate = Date;
3262 function ClockDate(year, month, date, hour, minute, second, ms) {
3263 // Defensive and verbose to avoid potential harm in passing
3264 // explicit undefined when user does not pass argument
3265 switch (arguments.length) {
3267 return new NativeDate(ClockDate.clock.now);
3269 return new NativeDate(year);
3271 return new NativeDate(year, month);
3273 return new NativeDate(year, month, date);
3275 return new NativeDate(year, month, date, hour);
3277 return new NativeDate(year, month, date, hour, minute);
3279 return new NativeDate(year, month, date, hour, minute, second);
3281 return new NativeDate(year, month, date, hour, minute, second, ms);
3285 return mirrorDateProperties(ClockDate, NativeDate);
3289 function mirrorDateProperties(target, source) {
3291 target.now = function now() {
3292 return target.clock.now;
3298 if (source.toSource) {
3299 target.toSource = function toSource() {
3300 return source.toSource();
3303 delete target.toSource;
3306 target.toString = function toString() {
3307 return source.toString();
3310 target.prototype = source.prototype;
3311 target.parse = source.parse;
3312 target.UTC = source.UTC;
3313 target.prototype.toUTCString = source.prototype.toUTCString;
3315 for (var prop in source) {
3316 if (source.hasOwnProperty(prop)) {
3317 target[prop] = source[prop];
3324 var methods = ["Date", "setTimeout", "setInterval",
3325 "clearTimeout", "clearInterval"];
3327 if (typeof global.setImmediate !== "undefined") {
3328 methods.push("setImmediate");
3331 if (typeof global.clearImmediate !== "undefined") {
3332 methods.push("clearImmediate");
3335 function restore() {
3338 for (var i = 0, l = this.methods.length; i < l; i++) {
3339 method = this.methods[i];
3341 if (global[method].hadOwnProperty) {
3342 global[method] = this["_" + method];
3345 delete global[method];
3350 // Prevent multiple executions which will completely remove these props
3354 function stubGlobal(method, clock) {
3355 clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
3356 clock["_" + method] = global[method];
3358 if (method == "Date") {
3359 var date = mirrorDateProperties(clock[method], global[method]);
3360 global[method] = date;
3362 global[method] = function () {
3363 return clock[method].apply(clock, arguments);
3366 for (var prop in clock[method]) {
3367 if (clock[method].hasOwnProperty(prop)) {
3368 global[method][prop] = clock[method][prop];
3373 global[method].clock = clock;
3376 sinon.useFakeTimers = function useFakeTimers(now) {
3377 var clock = sinon.clock.create(now);
3378 clock.restore = restore;
3379 clock.methods = Array.prototype.slice.call(arguments,
3380 typeof now == "number" ? 1 : 0);
3382 if (clock.methods.length === 0) {
3383 clock.methods = methods;
3386 for (var i = 0, l = clock.methods.length; i < l; i++) {
3387 stubGlobal(clock.methods[i], clock);
3392 }(typeof global != "undefined" && typeof global !== "function" ? global : this));
3395 setTimeout: setTimeout,
3396 clearTimeout: clearTimeout,
3397 setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
3398 clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
3399 setInterval: setInterval,
3400 clearInterval: clearInterval,
3404 if (typeof module !== 'undefined' && module.exports) {
3405 module.exports = sinon;
3408 /*jslint eqeqeq: false, onevar: false*/
3409 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
3411 * Minimal Event interface implementation
3413 * Original implementation by Sven Fuchs: https://gist.github.com/995028
3414 * Modifications and tests by Christian Johansen.
3416 * @author Sven Fuchs (svenfuchs@artweb-design.de)
3417 * @author Christian Johansen (christian@cjohansen.no)
3420 * Copyright (c) 2011 Sven Fuchs, Christian Johansen
3423 if (typeof sinon == "undefined") {
3430 sinon.Event = function Event(type, bubbles, cancelable, target) {
3431 this.initEvent(type, bubbles, cancelable, target);
3434 sinon.Event.prototype = {
3435 initEvent: function(type, bubbles, cancelable, target) {
3437 this.bubbles = bubbles;
3438 this.cancelable = cancelable;
3439 this.target = target;
3442 stopPropagation: function () {},
3444 preventDefault: function () {
3445 this.defaultPrevented = true;
3449 sinon.EventTarget = {
3450 addEventListener: function addEventListener(event, listener) {
3451 this.eventListeners = this.eventListeners || {};
3452 this.eventListeners[event] = this.eventListeners[event] || [];
3453 push.call(this.eventListeners[event], listener);
3456 removeEventListener: function removeEventListener(event, listener) {
3457 var listeners = this.eventListeners && this.eventListeners[event] || [];
3459 for (var i = 0, l = listeners.length; i < l; ++i) {
3460 if (listeners[i] == listener) {
3461 return listeners.splice(i, 1);
3466 dispatchEvent: function dispatchEvent(event) {
3467 var type = event.type;
3468 var listeners = this.eventListeners && this.eventListeners[type] || [];
3470 for (var i = 0; i < listeners.length; i++) {
3471 if (typeof listeners[i] == "function") {
3472 listeners[i].call(this, event);
3474 listeners[i].handleEvent(event);
3478 return !!event.defaultPrevented;
3484 * @depend ../../sinon.js
3487 /*jslint eqeqeq: false, onevar: false*/
3488 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
3490 * Fake XMLHttpRequest object
3492 * @author Christian Johansen (christian@cjohansen.no)
3495 * Copyright (c) 2010-2013 Christian Johansen
3498 // wrapper for global
3500 if (typeof sinon === "undefined") {
3504 var supportsProgress = typeof ProgressEvent !== "undefined";
3505 var supportsCustomEvent = typeof CustomEvent !== "undefined";
3506 sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
3507 var xhr = sinon.xhr;
3508 xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
3509 xhr.GlobalActiveXObject = global.ActiveXObject;
3510 xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
3511 xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
3512 xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
3513 ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
3514 xhr.supportsCORS = 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
3517 var unsafeHeaders = {
3518 "Accept-Charset": true,
3519 "Accept-Encoding": true,
3521 "Content-Length": true,
3524 "Content-Transfer-Encoding": true,
3532 "Transfer-Encoding": true,
3539 function FakeXMLHttpRequest() {
3540 this.readyState = FakeXMLHttpRequest.UNSENT;
3541 this.requestHeaders = {};
3542 this.requestBody = null;
3544 this.statusText = "";
3545 this.upload = new UploadProgress();
3546 if (sinon.xhr.supportsCORS) {
3547 this.withCredentials = false;
3552 var events = ["loadstart", "load", "abort", "loadend"];
3554 function addEventListener(eventName) {
3555 xhr.addEventListener(eventName, function (event) {
3556 var listener = xhr["on" + eventName];
3558 if (listener && typeof listener == "function") {
3564 for (var i = events.length - 1; i >= 0; i--) {
3565 addEventListener(events[i]);
3568 if (typeof FakeXMLHttpRequest.onCreate == "function") {
3569 FakeXMLHttpRequest.onCreate(this);
3573 // An upload object is created for each
3574 // FakeXMLHttpRequest and allows upload
3575 // events to be simulated using uploadProgress
3577 function UploadProgress() {
3578 this.eventListeners = {
3586 UploadProgress.prototype.addEventListener = function(event, listener) {
3587 this.eventListeners[event].push(listener);
3590 UploadProgress.prototype.removeEventListener = function(event, listener) {
3591 var listeners = this.eventListeners[event] || [];
3593 for (var i = 0, l = listeners.length; i < l; ++i) {
3594 if (listeners[i] == listener) {
3595 return listeners.splice(i, 1);
3600 UploadProgress.prototype.dispatchEvent = function(event) {
3601 var listeners = this.eventListeners[event.type] || [];
3603 for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
3608 function verifyState(xhr) {
3609 if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
3610 throw new Error("INVALID_STATE_ERR");
3614 throw new Error("INVALID_STATE_ERR");
3618 // filtering to enable a white-list version of Sinon FakeXhr,
3619 // where whitelisted requests are passed through to real XHR
3620 function each(collection, callback) {
3621 if (!collection) return;
3622 for (var i = 0, l = collection.length; i < l; i += 1) {
3623 callback(collection[i]);
3626 function some(collection, callback) {
3627 for (var index = 0; index < collection.length; index++) {
3628 if(callback(collection[index]) === true) return true;
3632 // largest arity in XHR is 5 - XHR#open
3633 var apply = function(obj,method,args) {
3634 switch(args.length) {
3635 case 0: return obj[method]();
3636 case 1: return obj[method](args[0]);
3637 case 2: return obj[method](args[0],args[1]);
3638 case 3: return obj[method](args[0],args[1],args[2]);
3639 case 4: return obj[method](args[0],args[1],args[2],args[3]);
3640 case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
3644 FakeXMLHttpRequest.filters = [];
3645 FakeXMLHttpRequest.addFilter = function(fn) {
3646 this.filters.push(fn)
3648 var IE6Re = /MSIE 6/;
3649 FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
3650 var xhr = new sinon.xhr.workingXHR();
3651 each(["open","setRequestHeader","send","abort","getResponseHeader",
3652 "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
3654 fakeXhr[method] = function() {
3655 return apply(xhr,method,arguments);
3659 var copyAttrs = function(args) {
3660 each(args, function(attr) {
3662 fakeXhr[attr] = xhr[attr]
3664 if(!IE6Re.test(navigator.userAgent)) throw e;
3669 var stateChange = function() {
3670 fakeXhr.readyState = xhr.readyState;
3671 if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
3672 copyAttrs(["status","statusText"]);
3674 if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
3675 copyAttrs(["responseText"]);
3677 if(xhr.readyState === FakeXMLHttpRequest.DONE) {
3678 copyAttrs(["responseXML"]);
3680 if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
3682 if(xhr.addEventListener) {
3683 for(var event in fakeXhr.eventListeners) {
3684 if(fakeXhr.eventListeners.hasOwnProperty(event)) {
3685 each(fakeXhr.eventListeners[event],function(handler) {
3686 xhr.addEventListener(event, handler);
3690 xhr.addEventListener("readystatechange",stateChange);
3692 xhr.onreadystatechange = stateChange;
3694 apply(xhr,"open",xhrArgs);
3696 FakeXMLHttpRequest.useFilters = false;
3698 function verifyRequestSent(xhr) {
3699 if (xhr.readyState == FakeXMLHttpRequest.DONE) {
3700 throw new Error("Request done");
3704 function verifyHeadersReceived(xhr) {
3705 if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
3706 throw new Error("No headers received");
3710 function verifyResponseBodyType(body) {
3711 if (typeof body != "string") {
3712 var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
3713 body + ", which is not a string.");
3714 error.name = "InvalidBodyException";
3719 sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
3722 open: function open(method, url, async, username, password) {
3723 this.method = method;
3725 this.async = typeof async == "boolean" ? async : true;
3726 this.username = username;
3727 this.password = password;
3728 this.responseText = null;
3729 this.responseXML = null;
3730 this.requestHeaders = {};
3731 this.sendFlag = false;
3732 if(sinon.FakeXMLHttpRequest.useFilters === true) {
3733 var xhrArgs = arguments;
3734 var defake = some(FakeXMLHttpRequest.filters,function(filter) {
3735 return filter.apply(this,xhrArgs)
3738 return sinon.FakeXMLHttpRequest.defake(this,arguments);
3741 this.readyStateChange(FakeXMLHttpRequest.OPENED);
3744 readyStateChange: function readyStateChange(state) {
3745 this.readyState = state;
3747 if (typeof this.onreadystatechange == "function") {
3749 this.onreadystatechange();
3751 sinon.logError("Fake XHR onreadystatechange handler", e);
3755 this.dispatchEvent(new sinon.Event("readystatechange"));
3757 switch (this.readyState) {
3758 case FakeXMLHttpRequest.DONE:
3759 this.dispatchEvent(new sinon.Event("load", false, false, this));
3760 this.dispatchEvent(new sinon.Event("loadend", false, false, this));
3761 this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
3762 if (supportsProgress) {
3763 this.upload.dispatchEvent(new sinon.Event("progress", {loaded: 100, total: 100}));
3769 setRequestHeader: function setRequestHeader(header, value) {
3772 if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
3773 throw new Error("Refused to set unsafe header \"" + header + "\"");
3776 if (this.requestHeaders[header]) {
3777 this.requestHeaders[header] += "," + value;
3779 this.requestHeaders[header] = value;
3784 setResponseHeaders: function setResponseHeaders(headers) {
3785 this.responseHeaders = {};
3787 for (var header in headers) {
3788 if (headers.hasOwnProperty(header)) {
3789 this.responseHeaders[header] = headers[header];
3794 this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
3796 this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
3800 // Currently treats ALL data as a DOMString (i.e. no Document)
3801 send: function send(data) {
3804 if (!/^(get|head)$/i.test(this.method)) {
3805 if (this.requestHeaders["Content-Type"]) {
3806 var value = this.requestHeaders["Content-Type"].split(";");
3807 this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
3809 this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
3812 this.requestBody = data;
3815 this.errorFlag = false;
3816 this.sendFlag = this.async;
3817 this.readyStateChange(FakeXMLHttpRequest.OPENED);
3819 if (typeof this.onSend == "function") {
3823 this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
3826 abort: function abort() {
3827 this.aborted = true;
3828 this.responseText = null;
3829 this.errorFlag = true;
3830 this.requestHeaders = {};
3832 if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
3833 this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
3834 this.sendFlag = false;
3837 this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
3839 this.dispatchEvent(new sinon.Event("abort", false, false, this));
3841 this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
3843 if (typeof this.onerror === "function") {
3848 getResponseHeader: function getResponseHeader(header) {
3849 if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
3853 if (/^Set-Cookie2?$/i.test(header)) {
3857 header = header.toLowerCase();
3859 for (var h in this.responseHeaders) {
3860 if (h.toLowerCase() == header) {
3861 return this.responseHeaders[h];
3868 getAllResponseHeaders: function getAllResponseHeaders() {
3869 if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
3875 for (var header in this.responseHeaders) {
3876 if (this.responseHeaders.hasOwnProperty(header) &&
3877 !/^Set-Cookie2?$/i.test(header)) {
3878 headers += header + ": " + this.responseHeaders[header] + "\r\n";
3885 setResponseBody: function setResponseBody(body) {
3886 verifyRequestSent(this);
3887 verifyHeadersReceived(this);
3888 verifyResponseBodyType(body);
3890 var chunkSize = this.chunkSize || 10;
3892 this.responseText = "";
3896 this.readyStateChange(FakeXMLHttpRequest.LOADING);
3899 this.responseText += body.substring(index, index + chunkSize);
3901 } while (index < body.length);
3903 var type = this.getResponseHeader("Content-Type");
3905 if (this.responseText &&
3906 (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
3908 this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
3910 // Unable to parse XML - no biggie
3915 this.readyStateChange(FakeXMLHttpRequest.DONE);
3917 this.readyState = FakeXMLHttpRequest.DONE;
3921 respond: function respond(status, headers, body) {
3922 this.status = typeof status == "number" ? status : 200;
3923 this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
3924 this.setResponseHeaders(headers || {});
3925 this.setResponseBody(body || "");
3928 uploadProgress: function uploadProgress(progressEventRaw) {
3929 if (supportsProgress) {
3930 this.upload.dispatchEvent(new sinon.Event("progress", progressEventRaw));
3934 uploadError: function uploadError(error) {
3935 if (supportsCustomEvent) {
3936 this.upload.dispatchEvent(new sinon.Event("error", {"detail": error}));
3941 sinon.extend(FakeXMLHttpRequest, {
3944 HEADERS_RECEIVED: 2,
3949 // Borrowed from JSpec
3950 FakeXMLHttpRequest.parseXML = function parseXML(text) {
3953 if (typeof DOMParser != "undefined") {
3954 var parser = new DOMParser();
3955 xmlDoc = parser.parseFromString(text, "text/xml");
3957 xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
3958 xmlDoc.async = "false";
3959 xmlDoc.loadXML(text);
3965 FakeXMLHttpRequest.statusCodes = {
3967 101: "Switching Protocols",
3971 203: "Non-Authoritative Information",
3973 205: "Reset Content",
3974 206: "Partial Content",
3975 300: "Multiple Choice",
3976 301: "Moved Permanently",
3979 304: "Not Modified",
3981 307: "Temporary Redirect",
3983 401: "Unauthorized",
3984 402: "Payment Required",
3987 405: "Method Not Allowed",
3988 406: "Not Acceptable",
3989 407: "Proxy Authentication Required",
3990 408: "Request Timeout",
3993 411: "Length Required",
3994 412: "Precondition Failed",
3995 413: "Request Entity Too Large",
3996 414: "Request-URI Too Long",
3997 415: "Unsupported Media Type",
3998 416: "Requested Range Not Satisfiable",
3999 417: "Expectation Failed",
4000 422: "Unprocessable Entity",
4001 500: "Internal Server Error",
4002 501: "Not Implemented",
4004 503: "Service Unavailable",
4005 504: "Gateway Timeout",
4006 505: "HTTP Version Not Supported"
4009 sinon.useFakeXMLHttpRequest = function () {
4010 sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
4011 if (xhr.supportsXHR) {
4012 global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
4015 if (xhr.supportsActiveX) {
4016 global.ActiveXObject = xhr.GlobalActiveXObject;
4019 delete sinon.FakeXMLHttpRequest.restore;
4021 if (keepOnCreate !== true) {
4022 delete sinon.FakeXMLHttpRequest.onCreate;
4025 if (xhr.supportsXHR) {
4026 global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
4029 if (xhr.supportsActiveX) {
4030 global.ActiveXObject = function ActiveXObject(objId) {
4031 if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
4033 return new sinon.FakeXMLHttpRequest();
4036 return new xhr.GlobalActiveXObject(objId);
4040 return sinon.FakeXMLHttpRequest;
4043 sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
4045 })(typeof global === "object" ? global : this);
4047 if (typeof module !== 'undefined' && module.exports) {
4048 module.exports = sinon;
4052 * @depend fake_xml_http_request.js
4054 /*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
4055 /*global module, require, window*/
4057 * The Sinon "server" mimics a web server that receives requests from
4058 * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
4059 * both synchronously and asynchronously. To respond synchronuously, canned
4060 * answers have to be provided upfront.
4062 * @author Christian Johansen (christian@cjohansen.no)
4065 * Copyright (c) 2010-2013 Christian Johansen
4068 if (typeof sinon == "undefined") {
4072 sinon.fakeServer = (function () {
4076 function create(proto) {
4077 F.prototype = proto;
4081 function responseArray(handler) {
4082 var response = handler;
4084 if (Object.prototype.toString.call(handler) != "[object Array]") {
4085 response = [200, {}, handler];
4088 if (typeof response[2] != "string") {
4089 throw new TypeError("Fake server response body should be string, but was " +
4090 typeof response[2]);
4096 var wloc = typeof window !== "undefined" ? window.location : {};
4097 var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
4099 function matchOne(response, reqMethod, reqUrl) {
4100 var rmeth = response.method;
4101 var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
4102 var url = response.url;
4103 var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
4105 return matchMethod && matchUrl;
4108 function match(response, request) {
4109 var requestUrl = request.url;
4111 if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
4112 requestUrl = requestUrl.replace(rCurrLoc, "");
4115 if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
4116 if (typeof response.response == "function") {
4117 var ru = response.url;
4118 var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
4119 return response.response.apply(response, args);
4128 function log(response, request) {
4131 str = "Request:\n" + sinon.format(request) + "\n\n";
4132 str += "Response:\n" + sinon.format(response) + "\n\n";
4138 create: function () {
4139 var server = create(this);
4140 this.xhr = sinon.useFakeXMLHttpRequest();
4141 server.requests = [];
4143 this.xhr.onCreate = function (xhrObj) {
4144 server.addRequest(xhrObj);
4150 addRequest: function addRequest(xhrObj) {
4152 push.call(this.requests, xhrObj);
4154 xhrObj.onSend = function () {
4155 server.handleRequest(this);
4157 if (server.autoRespond && !server.responding) {
4158 setTimeout(function () {
4159 server.responding = false;
4161 }, server.autoRespondAfter || 10);
4163 server.responding = true;
4168 getHTTPMethod: function getHTTPMethod(request) {
4169 if (this.fakeHTTPMethods && /post/i.test(request.method)) {
4170 var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
4171 return !!matches ? matches[1] : request.method;
4174 return request.method;
4177 handleRequest: function handleRequest(xhr) {
4183 push.call(this.queue, xhr);
4185 this.processRequest(xhr);
4189 respondWith: function respondWith(method, url, body) {
4190 if (arguments.length == 1 && typeof method != "function") {
4191 this.response = responseArray(method);
4195 if (!this.responses) { this.responses = []; }
4197 if (arguments.length == 1) {
4199 url = method = null;
4202 if (arguments.length == 2) {
4208 push.call(this.responses, {
4211 response: typeof body == "function" ? body : responseArray(body)
4215 respond: function respond() {
4216 if (arguments.length > 0) this.respondWith.apply(this, arguments);
4217 var queue = this.queue || [];
4218 var requests = queue.splice(0);
4221 while(request = requests.shift()) {
4222 this.processRequest(request);
4226 processRequest: function processRequest(request) {
4228 if (request.aborted) {
4232 var response = this.response || [404, {}, ""];
4234 if (this.responses) {
4235 for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
4236 if (match.call(this, this.responses[i], request)) {
4237 response = this.responses[i].response;
4243 if (request.readyState != 4) {
4244 log(response, request);
4246 request.respond(response[0], response[1], response[2]);
4249 sinon.logError("Fake server request processing", e);
4253 restore: function restore() {
4254 return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
4259 if (typeof module !== 'undefined' && module.exports) {
4260 module.exports = sinon;
4264 * @depend fake_server.js
4265 * @depend fake_timers.js
4267 /*jslint browser: true, eqeqeq: false, onevar: false*/
4270 * Add-on for sinon.fakeServer that automatically handles a fake timer along with
4271 * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
4272 * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
4273 * it polls the object for completion with setInterval. Dispite the direct
4274 * motivation, there is nothing jQuery-specific in this file, so it can be used
4275 * in any environment where the ajax implementation depends on setInterval or
4278 * @author Christian Johansen (christian@cjohansen.no)
4281 * Copyright (c) 2010-2013 Christian Johansen
4285 function Server() {}
4286 Server.prototype = sinon.fakeServer;
4288 sinon.fakeServerWithClock = new Server();
4290 sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
4292 if (typeof setTimeout.clock == "object") {
4293 this.clock = setTimeout.clock;
4295 this.clock = sinon.useFakeTimers();
4296 this.resetClock = true;
4299 if (!this.longestTimeout) {
4300 var clockSetTimeout = this.clock.setTimeout;
4301 var clockSetInterval = this.clock.setInterval;
4304 this.clock.setTimeout = function (fn, timeout) {
4305 server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
4307 return clockSetTimeout.apply(this, arguments);
4310 this.clock.setInterval = function (fn, timeout) {
4311 server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
4313 return clockSetInterval.apply(this, arguments);
4318 return sinon.fakeServer.addRequest.call(this, xhr);
4321 sinon.fakeServerWithClock.respond = function respond() {
4322 var returnVal = sinon.fakeServer.respond.apply(this, arguments);
4325 this.clock.tick(this.longestTimeout || 0);
4326 this.longestTimeout = 0;
4328 if (this.resetClock) {
4329 this.clock.restore();
4330 this.resetClock = false;
4337 sinon.fakeServerWithClock.restore = function restore() {
4339 this.clock.restore();
4342 return sinon.fakeServer.restore.apply(this, arguments);
4347 * @depend ../sinon.js
4348 * @depend collection.js
4349 * @depend util/fake_timers.js
4350 * @depend util/fake_server_with_clock.js
4352 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
4353 /*global require, module*/
4355 * Manages fake collections as well as fake utilities such as Sinon's
4356 * timers and fake XHR implementation in one convenient object.
4358 * @author Christian Johansen (christian@cjohansen.no)
4361 * Copyright (c) 2010-2013 Christian Johansen
4364 if (typeof module !== 'undefined' && module.exports) {
4365 var sinon = require("../sinon");
4366 sinon.extend(sinon, require("./util/fake_timers"));
4372 function exposeValue(sandbox, config, key, value) {
4377 if (config.injectInto && !(key in config.injectInto)) {
4378 config.injectInto[key] = value;
4379 sandbox.injectedKeys.push(key);
4381 push.call(sandbox.args, value);
4385 function prepareSandboxFromConfig(config) {
4386 var sandbox = sinon.create(sinon.sandbox);
4388 if (config.useFakeServer) {
4389 if (typeof config.useFakeServer == "object") {
4390 sandbox.serverPrototype = config.useFakeServer;
4393 sandbox.useFakeServer();
4396 if (config.useFakeTimers) {
4397 if (typeof config.useFakeTimers == "object") {
4398 sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
4400 sandbox.useFakeTimers();
4407 sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
4408 useFakeTimers: function useFakeTimers() {
4409 this.clock = sinon.useFakeTimers.apply(sinon, arguments);
4411 return this.add(this.clock);
4414 serverPrototype: sinon.fakeServer,
4416 useFakeServer: function useFakeServer() {
4417 var proto = this.serverPrototype || sinon.fakeServer;
4419 if (!proto || !proto.create) {
4423 this.server = proto.create();
4424 return this.add(this.server);
4427 inject: function (obj) {
4428 sinon.collection.inject.call(this, obj);
4431 obj.clock = this.clock;
4435 obj.server = this.server;
4436 obj.requests = this.server.requests;
4442 restore: function () {
4443 sinon.collection.restore.apply(this, arguments);
4444 this.restoreContext();
4447 restoreContext: function () {
4448 if (this.injectedKeys) {
4449 for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
4450 delete this.injectInto[this.injectedKeys[i]];
4452 this.injectedKeys = [];
4456 create: function (config) {
4458 return sinon.create(sinon.sandbox);
4461 var sandbox = prepareSandboxFromConfig(config);
4462 sandbox.args = sandbox.args || [];
4463 sandbox.injectedKeys = [];
4464 sandbox.injectInto = config.injectInto;
4465 var prop, value, exposed = sandbox.inject({});
4467 if (config.properties) {
4468 for (var i = 0, l = config.properties.length; i < l; i++) {
4469 prop = config.properties[i];
4470 value = exposed[prop] || prop == "sandbox" && sandbox;
4471 exposeValue(sandbox, config, prop, value);
4474 exposeValue(sandbox, config, "sandbox", value);
4481 sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
4483 if (typeof module !== 'undefined' && module.exports) {
4484 module.exports = sinon.sandbox;
4489 * @depend ../sinon.js
4492 * @depend sandbox.js
4494 /*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
4495 /*global module, require, sinon*/
4497 * Test function, sandboxes fakes
4499 * @author Christian Johansen (christian@cjohansen.no)
4502 * Copyright (c) 2010-2013 Christian Johansen
4506 var commonJSModule = typeof module !== 'undefined' && module.exports;
4508 if (!sinon && commonJSModule) {
4509 sinon = require("../sinon");
4516 function test(callback) {
4517 var type = typeof callback;
4519 if (type != "function") {
4520 throw new TypeError("sinon.test needs to wrap a test function, got " + type);
4523 return function () {
4524 var config = sinon.getConfig(sinon.config);
4525 config.injectInto = config.injectIntoThis && this || config.injectInto;
4526 var sandbox = sinon.sandbox.create(config);
4527 var exception, result;
4528 var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
4531 result = callback.apply(this, args);
4536 if (typeof exception !== "undefined") {
4541 sandbox.verifyAndRestore();
4549 injectIntoThis: true,
4551 properties: ["spy", "stub", "mock", "clock", "server", "requests"],
4552 useFakeTimers: true,
4556 if (commonJSModule) {
4557 module.exports = test;
4561 }(typeof sinon == "object" && sinon || null));
4564 * @depend ../sinon.js
4567 /*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
4568 /*global module, require, sinon*/
4570 * Test case, sandboxes all test functions
4572 * @author Christian Johansen (christian@cjohansen.no)
4575 * Copyright (c) 2010-2013 Christian Johansen
4579 var commonJSModule = typeof module !== 'undefined' && module.exports;
4581 if (!sinon && commonJSModule) {
4582 sinon = require("../sinon");
4585 if (!sinon || !Object.prototype.hasOwnProperty) {
4589 function createTest(property, setUp, tearDown) {
4590 return function () {
4592 setUp.apply(this, arguments);
4595 var exception, result;
4598 result = property.apply(this, arguments);
4604 tearDown.apply(this, arguments);
4615 function testCase(tests, prefix) {
4617 if (!tests || typeof tests != "object") {
4618 throw new TypeError("sinon.testCase needs an object with test functions");
4622 prefix = prefix || "test";
4623 var rPrefix = new RegExp("^" + prefix);
4624 var methods = {}, testName, property, method;
4625 var setUp = tests.setUp;
4626 var tearDown = tests.tearDown;
4628 for (testName in tests) {
4629 if (tests.hasOwnProperty(testName)) {
4630 property = tests[testName];
4632 if (/^(setUp|tearDown)$/.test(testName)) {
4636 if (typeof property == "function" && rPrefix.test(testName)) {
4639 if (setUp || tearDown) {
4640 method = createTest(property, setUp, tearDown);
4643 methods[testName] = sinon.test(method);
4645 methods[testName] = tests[testName];
4653 if (commonJSModule) {
4654 module.exports = testCase;
4656 sinon.testCase = testCase;
4658 }(typeof sinon == "object" && sinon || null));
4661 * @depend ../sinon.js
4664 /*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
4665 /*global module, require, sinon*/
4667 * Assertions matching the test spy retrieval interface.
4669 * @author Christian Johansen (christian@cjohansen.no)
4672 * Copyright (c) 2010-2013 Christian Johansen
4675 (function (sinon, global) {
4676 var commonJSModule = typeof module !== "undefined" && module.exports;
4677 var slice = Array.prototype.slice;
4680 if (!sinon && commonJSModule) {
4681 sinon = require("../sinon");
4688 function verifyIsStub() {
4691 for (var i = 0, l = arguments.length; i < l; ++i) {
4692 method = arguments[i];
4695 assert.fail("fake is not a spy");
4698 if (typeof method != "function") {
4699 assert.fail(method + " is not a function");
4702 if (typeof method.getCall != "function") {
4703 assert.fail(method + " is not stubbed");
4708 function failAssertion(object, msg) {
4709 object = object || global;
4710 var failMethod = object.fail || assert.fail;
4711 failMethod.call(object, msg);
4714 function mirrorPropAsAssertion(name, method, message) {
4715 if (arguments.length == 2) {
4720 assert[name] = function (fake) {
4723 var args = slice.call(arguments, 1);
4726 if (typeof method == "function") {
4727 failed = !method(fake);
4729 failed = typeof fake[method] == "function" ?
4730 !fake[method].apply(fake, args) : !fake[method];
4734 failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
4741 function exposedName(prefix, prop) {
4742 return !prefix || /^fail/.test(prop) ? prop :
4743 prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
4747 failException: "AssertError",
4749 fail: function fail(message) {
4750 var error = new Error(message);
4751 error.name = this.failException || assert.failException;
4756 pass: function pass(assertion) {},
4758 callOrder: function assertCallOrder() {
4759 verifyIsStub.apply(null, arguments);
4760 var expected = "", actual = "";
4762 if (!sinon.calledInOrder(arguments)) {
4764 expected = [].join.call(arguments, ", ");
4765 var calls = slice.call(arguments);
4766 var i = calls.length;
4768 if (!calls[--i].called) {
4772 actual = sinon.orderByFirstCall(calls).join(", ");
4774 // If this fails, we'll just fall back to the blank string
4777 failAssertion(this, "expected " + expected + " to be " +
4778 "called in order but were called as " + actual);
4780 assert.pass("callOrder");
4784 callCount: function assertCallCount(method, count) {
4785 verifyIsStub(method);
4787 if (method.callCount != count) {
4788 var msg = "expected %n to be called " + sinon.timesInWords(count) +
4789 " but was called %c%C";
4790 failAssertion(this, method.printf(msg));
4792 assert.pass("callCount");
4796 expose: function expose(target, options) {
4798 throw new TypeError("target is null or undefined");
4801 var o = options || {};
4802 var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
4803 var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
4805 for (var method in this) {
4806 if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
4807 target[exposedName(prefix, method)] = this[method];
4815 mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
4816 mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
4817 "expected %n to not have been called but was called %c%C");
4818 mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
4819 mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
4820 mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
4821 mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
4822 mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
4823 mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
4824 mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
4825 mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
4826 mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
4827 mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
4828 mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
4829 mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
4830 mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
4831 mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
4832 mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
4833 mirrorPropAsAssertion("threw", "%n did not throw exception%C");
4834 mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
4836 if (commonJSModule) {
4837 module.exports = assert;
4839 sinon.assert = assert;
4841 }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
4843 return sinon;}.call(typeof window != 'undefined' && window || {}));