/** * Sinon.JS 1.15.4, 2015/06/27 * * @author Christian Johansen (christian@cjohansen.no) * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS * * (The BSD License) * * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Christian Johansen nor the names of his contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ (function (root, factory) { 'use strict'; if (typeof define === 'function' && define.amd) { define('sinon', [], function () { return (root.sinon = factory()); }); } else if (typeof exports === 'object') { module.exports = factory(); } else { root.sinon = factory(); } }(this, function () { 'use strict'; var samsam, formatio, lolex; (function () { function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else if (typeof deps === "function" && mod.length === 0) { lolex = deps(); } else if (typeof fn === "function") { formatio = fn(samsam); } } define.amd = {}; ((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) || (typeof module === "object" && function (m) { module.exports = m(); }) || // Node function (m) { this.samsam = m(); } // Browser globals )(function () { var o = Object.prototype; var div = typeof document !== "undefined" && document.createElement("div"); function isNaN(value) { // Unlike global isNaN, this avoids type coercion // typeof check avoids IE host object issues, hat tip to // lodash var val = value; // JsLint thinks value !== value is "weird" return typeof value === "number" && value !== val; } function getClass(value) { // Returns the internal [[Class]] by calling Object.prototype.toString // with the provided value as this. Return value is a string, naming the // internal class, e.g. "Array" return o.toString.call(value).split(/[ \]]/)[1]; } /** * @name samsam.isArguments * @param Object object * * Returns ``true`` if ``object`` is an ``arguments`` object, * ``false`` otherwise. */ function isArguments(object) { if (getClass(object) === 'Arguments') { return true; } if (typeof object !== "object" || typeof object.length !== "number" || getClass(object) === "Array") { return false; } if (typeof object.callee == "function") { return true; } try { object[object.length] = 6; delete object[object.length]; } catch (e) { return true; } return false; } /** * @name samsam.isElement * @param Object object * * Returns ``true`` if ``object`` is a DOM element node. Unlike * Underscore.js/lodash, this function will return ``false`` if ``object`` * is an *element-like* object, i.e. a regular object with a ``nodeType`` * property that holds the value ``1``. */ function isElement(object) { if (!object || object.nodeType !== 1 || !div) { return false; } try { object.appendChild(div); object.removeChild(div); } catch (e) { return false; } return true; } /** * @name samsam.keys * @param Object object * * Return an array of own property names. */ function keys(object) { var ks = [], prop; for (prop in object) { if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); } } return ks; } /** * @name samsam.isDate * @param Object value * * Returns true if the object is a ``Date``, or *date-like*. Duck typing * of date objects work by checking that the object has a ``getTime`` * function whose return value equals the return value from the object's * ``valueOf``. */ function isDate(value) { return typeof value.getTime == "function" && value.getTime() == value.valueOf(); } /** * @name samsam.isNegZero * @param Object value * * Returns ``true`` if ``value`` is ``-0``. */ function isNegZero(value) { return value === 0 && 1 / value === -Infinity; } /** * @name samsam.equal * @param Object obj1 * @param Object obj2 * * Returns ``true`` if two objects are strictly equal. Compared to * ``===`` there are two exceptions: * * - NaN is considered equal to NaN * - -0 and +0 are not considered equal */ function identical(obj1, obj2) { if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) { return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2); } } /** * @name samsam.deepEqual * @param Object obj1 * @param Object obj2 * * Deep equal comparison. Two values are "deep equal" if: * * - They are equal, according to samsam.identical * - They are both date objects representing the same time * - They are both arrays containing elements that are all deepEqual * - They are objects with the same set of properties, and each property * in ``obj1`` is deepEqual to the corresponding property in ``obj2`` * * Supports cyclic objects. */ function deepEqualCyclic(obj1, obj2) { // used for cyclic comparison // contain already visited objects var objects1 = [], objects2 = [], // contain pathes (position in the object structure) // of the already visited objects // indexes same as in objects arrays paths1 = [], paths2 = [], // contains combinations of already compared objects // in the manner: { "$1['ref']$2['ref']": true } compared = {}; /** * used to check, if the value of a property is an object * (cyclic logic is only needed for objects) * only needed for cyclic logic */ function isObject(value) { if (typeof value === 'object' && value !== null && !(value instanceof Boolean) && !(value instanceof Date) && !(value instanceof Number) && !(value instanceof RegExp) && !(value instanceof String)) { return true; } return false; } /** * returns the index of the given object in the * given objects array, -1 if not contained * only needed for cyclic logic */ function getIndex(objects, obj) { var i; for (i = 0; i < objects.length; i++) { if (objects[i] === obj) { return i; } } return -1; } // does the recursion for the deep equal check return (function deepEqual(obj1, obj2, path1, path2) { var type1 = typeof obj1; var type2 = typeof obj2; // == null also matches undefined if (obj1 === obj2 || isNaN(obj1) || isNaN(obj2) || obj1 == null || obj2 == null || type1 !== "object" || type2 !== "object") { return identical(obj1, obj2); } // Elements are only equal if identical(expected, actual) if (isElement(obj1) || isElement(obj2)) { return false; } var isDate1 = isDate(obj1), isDate2 = isDate(obj2); if (isDate1 || isDate2) { if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) { return false; } } if (obj1 instanceof RegExp && obj2 instanceof RegExp) { if (obj1.toString() !== obj2.toString()) { return false; } } var class1 = getClass(obj1); var class2 = getClass(obj2); var keys1 = keys(obj1); var keys2 = keys(obj2); if (isArguments(obj1) || isArguments(obj2)) { if (obj1.length !== obj2.length) { return false; } } else { if (type1 !== type2 || class1 !== class2 || keys1.length !== keys2.length) { return false; } } var key, i, l, // following vars are used for the cyclic logic value1, value2, isObject1, isObject2, index1, index2, newPath1, newPath2; for (i = 0, l = keys1.length; i < l; i++) { key = keys1[i]; if (!o.hasOwnProperty.call(obj2, key)) { return false; } // Start of the cyclic logic value1 = obj1[key]; value2 = obj2[key]; isObject1 = isObject(value1); isObject2 = isObject(value2); // determine, if the objects were already visited // (it's faster to check for isObject first, than to // get -1 from getIndex for non objects) index1 = isObject1 ? getIndex(objects1, value1) : -1; index2 = isObject2 ? getIndex(objects2, value2) : -1; // determine the new pathes of the objects // - for non cyclic objects the current path will be extended // by current property name // - for cyclic objects the stored path is taken newPath1 = index1 !== -1 ? paths1[index1] : path1 + '[' + JSON.stringify(key) + ']'; newPath2 = index2 !== -1 ? paths2[index2] : path2 + '[' + JSON.stringify(key) + ']'; // stop recursion if current objects are already compared if (compared[newPath1 + newPath2]) { return true; } // remember the current objects and their pathes if (index1 === -1 && isObject1) { objects1.push(value1); paths1.push(newPath1); } if (index2 === -1 && isObject2) { objects2.push(value2); paths2.push(newPath2); } // remember that the current objects are already compared if (isObject1 && isObject2) { compared[newPath1 + newPath2] = true; } // End of cyclic logic // neither value1 nor value2 is a cycle // continue with next level if (!deepEqual(value1, value2, newPath1, newPath2)) { return false; } } return true; }(obj1, obj2, '$1', '$2')); } var match; function arrayContains(array, subset) { if (subset.length === 0) { return true; } var i, l, j, k; for (i = 0, l = array.length; i < l; ++i) { if (match(array[i], subset[0])) { for (j = 0, k = subset.length; j < k; ++j) { if (!match(array[i + j], subset[j])) { return false; } } return true; } } return false; } /** * @name samsam.match * @param Object object * @param Object matcher * * Compare arbitrary value ``object`` with matcher. */ match = function match(object, matcher) { if (matcher && typeof matcher.test === "function") { return matcher.test(object); } if (typeof matcher === "function") { return matcher(object) === true; } if (typeof matcher === "string") { matcher = matcher.toLowerCase(); var notNull = typeof object === "string" || !!object; return notNull && (String(object)).toLowerCase().indexOf(matcher) >= 0; } if (typeof matcher === "number") { return matcher === object; } if (typeof matcher === "boolean") { return matcher === object; } if (typeof(matcher) === "undefined") { return typeof(object) === "undefined"; } if (matcher === null) { return object === null; } if (getClass(object) === "Array" && getClass(matcher) === "Array") { return arrayContains(object, matcher); } if (matcher && typeof matcher === "object") { if (matcher === object) { return true; } var prop; for (prop in matcher) { var value = object[prop]; if (typeof value === "undefined" && typeof object.getAttribute === "function") { value = object.getAttribute(prop); } if (matcher[prop] === null || typeof matcher[prop] === 'undefined') { if (value !== matcher[prop]) { return false; } } else if (typeof value === "undefined" || !match(value, matcher[prop])) { return false; } } return true; } throw new Error("Matcher was not a string, a number, a " + "function, a boolean or an object"); }; return { isArguments: isArguments, isElement: isElement, isDate: isDate, isNegZero: isNegZero, identical: identical, deepEqual: deepEqualCyclic, match: match, keys: keys }; }); ((typeof define === "function" && define.amd && function (m) { define("formatio", ["samsam"], m); }) || (typeof module === "object" && function (m) { module.exports = m(require("samsam")); }) || function (m) { this.formatio = m(this.samsam); } )(function (samsam) { var formatio = { excludeConstructors: ["Object", /^.$/], quoteStrings: true, limitChildrenCount: 0 }; var hasOwn = Object.prototype.hasOwnProperty; var specialObjects = []; if (typeof global !== "undefined") { specialObjects.push({ object: global, value: "[object global]" }); } if (typeof document !== "undefined") { specialObjects.push({ object: document, value: "[object HTMLDocument]" }); } if (typeof window !== "undefined") { specialObjects.push({ object: window, value: "[object Window]" }); } function functionName(func) { if (!func) { return ""; } if (func.displayName) { return func.displayName; } if (func.name) { return func.name; } var matches = func.toString().match(/function\s+([^\(]+)/m); return (matches && matches[1]) || ""; } function constructorName(f, object) { var name = functionName(object && object.constructor); var excludes = f.excludeConstructors || formatio.excludeConstructors || []; var i, l; for (i = 0, l = excludes.length; i < l; ++i) { if (typeof excludes[i] === "string" && excludes[i] === name) { return ""; } else if (excludes[i].test && excludes[i].test(name)) { return ""; } } return name; } function isCircular(object, objects) { if (typeof object !== "object") { return false; } var i, l; for (i = 0, l = objects.length; i < l; ++i) { if (objects[i] === object) { return true; } } return false; } function ascii(f, object, processed, indent) { if (typeof object === "string") { var qs = f.quoteStrings; var quote = typeof qs !== "boolean" || qs; return processed || quote ? '"' + object + '"' : object; } if (typeof object === "function" && !(object instanceof RegExp)) { return ascii.func(object); } processed = processed || []; if (isCircular(object, processed)) { return "[Circular]"; } if (Object.prototype.toString.call(object) === "[object Array]") { return ascii.array.call(f, object, processed); } if (!object) { return String((1/object) === -Infinity ? "-0" : object); } if (samsam.isElement(object)) { return ascii.element(object); } if (typeof object.toString === "function" && object.toString !== Object.prototype.toString) { return object.toString(); } var i, l; for (i = 0, l = specialObjects.length; i < l; i++) { if (object === specialObjects[i].object) { return specialObjects[i].value; } } return ascii.object.call(f, object, processed, indent); } ascii.func = function (func) { return "function " + functionName(func) + "() {}"; }; ascii.array = function (array, processed) { processed = processed || []; processed.push(array); var pieces = []; var i, l; l = (this.limitChildrenCount > 0) ? Math.min(this.limitChildrenCount, array.length) : array.length; for (i = 0; i < l; ++i) { pieces.push(ascii(this, array[i], processed)); } if(l < array.length) pieces.push("[... " + (array.length - l) + " more elements]"); return "[" + pieces.join(", ") + "]"; }; ascii.object = function (object, processed, indent) { processed = processed || []; processed.push(object); indent = indent || 0; var pieces = [], properties = samsam.keys(object).sort(); var length = 3; var prop, str, obj, i, k, l; l = (this.limitChildrenCount > 0) ? Math.min(this.limitChildrenCount, properties.length) : properties.length; for (i = 0; i < l; ++i) { prop = properties[i]; obj = object[prop]; if (isCircular(obj, processed)) { str = "[Circular]"; } else { str = ascii(this, obj, processed, indent + 2); } str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str; length += str.length; pieces.push(str); } var cons = constructorName(this, object); var prefix = cons ? "[" + cons + "] " : ""; var is = ""; for (i = 0, k = indent; i < k; ++i) { is += " "; } if(l < properties.length) pieces.push("[... " + (properties.length - l) + " more elements]"); if (length + indent > 80) { return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + is + "}"; } return prefix + "{ " + pieces.join(", ") + " }"; }; ascii.element = function (element) { var tagName = element.tagName.toLowerCase(); var attrs = element.attributes, attr, pairs = [], attrName, i, l, val; for (i = 0, l = attrs.length; i < l; ++i) { attr = attrs.item(i); attrName = attr.nodeName.toLowerCase().replace("html:", ""); val = attr.nodeValue; if (attrName !== "contenteditable" || val !== "inherit") { if (!!val) { pairs.push(attrName + "=\"" + val + "\""); } } } var formatted = "<" + tagName + (pairs.length > 0 ? " " : ""); var content = element.innerHTML; if (content.length > 20) { content = content.substr(0, 20) + "[...]"; } var res = formatted + pairs.join(" ") + ">" + content + ""; return res.replace(/ contentEditable="inherit"/, ""); }; function Formatio(options) { for (var opt in options) { this[opt] = options[opt]; } } Formatio.prototype = { functionName: functionName, configure: function (options) { return new Formatio(options); }, constructorName: function (object) { return constructorName(this, object); }, ascii: function (object, processed, indent) { return ascii(this, object, processed, indent); } }; return Formatio.prototype; }); !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.lolex=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { throw new Error("tick only understands numbers and 'h:m:s'"); } while (i--) { parsed = parseInt(strings[i], 10); if (parsed >= 60) { throw new Error("Invalid time " + str); } ms += parsed * Math.pow(60, (l - i - 1)); } return ms * 1000; } /** * Used to grok the `now` parameter to createClock. */ function getEpoch(epoch) { if (!epoch) { return 0; } if (typeof epoch.getTime === "function") { return epoch.getTime(); } if (typeof epoch === "number") { return epoch; } throw new TypeError("now should be milliseconds since UNIX epoch"); } function inRange(from, to, timer) { return timer && timer.callAt >= from && timer.callAt <= to; } function mirrorDateProperties(target, source) { if (source.now) { target.now = function now() { return target.clock.now; }; } else { delete target.now; } if (source.toSource) { target.toSource = function toSource() { return source.toSource(); }; } else { delete target.toSource; } target.toString = function toString() { return source.toString(); }; target.prototype = source.prototype; target.parse = source.parse; target.UTC = source.UTC; target.prototype.toUTCString = source.prototype.toUTCString; for (var prop in source) { if (source.hasOwnProperty(prop)) { target[prop] = source[prop]; } } return target; } function createDate() { function ClockDate(year, month, date, hour, minute, second, ms) { // Defensive and verbose to avoid potential harm in passing // explicit undefined when user does not pass argument switch (arguments.length) { case 0: return new NativeDate(ClockDate.clock.now); case 1: return new NativeDate(year); case 2: return new NativeDate(year, month); case 3: return new NativeDate(year, month, date); case 4: return new NativeDate(year, month, date, hour); case 5: return new NativeDate(year, month, date, hour, minute); case 6: return new NativeDate(year, month, date, hour, minute, second); default: return new NativeDate(year, month, date, hour, minute, second, ms); } } return mirrorDateProperties(ClockDate, NativeDate); } function addTimer(clock, timer) { if (typeof timer.func === "undefined") { throw new Error("Callback must be provided to timer calls"); } if (!clock.timers) { clock.timers = {}; } timer.id = id++; timer.createdAt = clock.now; timer.callAt = clock.now + (timer.delay || 0); clock.timers[timer.id] = timer; if (addTimerReturnsObject) { return { id: timer.id, ref: function() {}, unref: function() {} }; } else { return timer.id; } } function firstTimerInRange(clock, from, to) { var timers = clock.timers, timer = null; for (var id in timers) { if (!inRange(from, to, timers[id])) { continue; } if (!timer || ~compareTimers(timer, timers[id])) { timer = timers[id]; } } return timer; } function compareTimers(a, b) { // Sort first by absolute timing if (a.callAt < b.callAt) { return -1; } if (a.callAt > b.callAt) { return 1; } // Sort next by immediate, immediate timers take precedence if (a.immediate && !b.immediate) { return -1; } if (!a.immediate && b.immediate) { return 1; } // Sort next by creation time, earlier-created timers take precedence if (a.createdAt < b.createdAt) { return -1; } if (a.createdAt > b.createdAt) { return 1; } // Sort next by id, lower-id timers take precedence if (a.id < b.id) { return -1; } if (a.id > b.id) { return 1; } // As timer ids are unique, no fallback `0` is necessary } function callTimer(clock, timer) { if (typeof timer.interval == "number") { clock.timers[timer.id].callAt += timer.interval; } else { delete clock.timers[timer.id]; } try { if (typeof timer.func == "function") { timer.func.apply(null, timer.args); } else { eval(timer.func); } } catch (e) { var exception = e; } if (!clock.timers[timer.id]) { if (exception) { throw exception; } return; } if (exception) { throw exception; } } function uninstall(clock, target) { var method; for (var i = 0, l = clock.methods.length; i < l; i++) { method = clock.methods[i]; if (target[method].hadOwnProperty) { target[method] = clock["_" + method]; } else { try { delete target[method]; } catch (e) {} } } // Prevent multiple executions which will completely remove these props clock.methods = []; } function hijackMethod(target, method, clock) { clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method); clock["_" + method] = target[method]; if (method == "Date") { var date = mirrorDateProperties(clock[method], target[method]); target[method] = date; } else { target[method] = function () { return clock[method].apply(clock, arguments); }; for (var prop in clock[method]) { if (clock[method].hasOwnProperty(prop)) { target[method][prop] = clock[method][prop]; } } } target[method].clock = clock; } var timers = { setTimeout: setTimeout, clearTimeout: clearTimeout, setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined), setInterval: setInterval, clearInterval: clearInterval, Date: Date }; var keys = Object.keys || function (obj) { var ks = []; for (var key in obj) { ks.push(key); } return ks; }; exports.timers = timers; var createClock = exports.createClock = function (now) { var clock = { now: getEpoch(now), timeouts: {}, Date: createDate() }; clock.Date.clock = clock; clock.setTimeout = function setTimeout(func, timeout) { return addTimer(clock, { func: func, args: Array.prototype.slice.call(arguments, 2), delay: timeout }); }; clock.clearTimeout = function clearTimeout(timerId) { if (!timerId) { // null appears to be allowed in most browsers, and appears to be // relied upon by some libraries, like Bootstrap carousel return; } if (!clock.timers) { clock.timers = []; } // in Node, timerId is an object with .ref()/.unref(), and // its .id field is the actual timer id. if (typeof timerId === "object") { timerId = timerId.id } if (timerId in clock.timers) { delete clock.timers[timerId]; } }; clock.setInterval = function setInterval(func, timeout) { return addTimer(clock, { func: func, args: Array.prototype.slice.call(arguments, 2), delay: timeout, interval: timeout }); }; clock.clearInterval = function clearInterval(timerId) { clock.clearTimeout(timerId); }; clock.setImmediate = function setImmediate(func) { return addTimer(clock, { func: func, args: Array.prototype.slice.call(arguments, 1), immediate: true }); }; clock.clearImmediate = function clearImmediate(timerId) { clock.clearTimeout(timerId); }; clock.tick = function tick(ms) { ms = typeof ms == "number" ? ms : parseTime(ms); var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now; var timer = firstTimerInRange(clock, tickFrom, tickTo); var firstException; while (timer && tickFrom <= tickTo) { if (clock.timers[timer.id]) { tickFrom = clock.now = timer.callAt; try { callTimer(clock, timer); } catch (e) { firstException = firstException || e; } } timer = firstTimerInRange(clock, previous, tickTo); previous = tickFrom; } clock.now = tickTo; if (firstException) { throw firstException; } return clock.now; }; clock.reset = function reset() { clock.timers = {}; }; return clock; }; exports.install = function install(target, now, toFake) { if (typeof target === "number") { toFake = now; now = target; target = null; } if (!target) { target = global; } var clock = createClock(now); clock.uninstall = function () { uninstall(clock, target); }; clock.methods = toFake || []; if (clock.methods.length === 0) { clock.methods = keys(timers); } for (var i = 0, l = clock.methods.length; i < l; i++) { hijackMethod(target, clock.methods[i], clock); } return clock; }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}]},{},[1])(1) }); })(); var define; /** * Sinon core utilities. For internal use only. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ var sinon = (function () { "use strict"; var sinon; var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { sinon = module.exports = require("./sinon/util/core"); require("./sinon/extend"); require("./sinon/typeOf"); require("./sinon/times_in_words"); require("./sinon/spy"); require("./sinon/call"); require("./sinon/behavior"); require("./sinon/stub"); require("./sinon/mock"); require("./sinon/collection"); require("./sinon/assert"); require("./sinon/sandbox"); require("./sinon/test"); require("./sinon/test_case"); require("./sinon/match"); require("./sinon/format"); require("./sinon/log_error"); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); sinon = module.exports; } else { sinon = {}; } return sinon; }()); /** * @depend ../../sinon.js */ /** * Sinon core utilities. For internal use only. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinon) { var div = typeof document != "undefined" && document.createElement("div"); var hasOwn = Object.prototype.hasOwnProperty; function isDOMNode(obj) { var success = false; try { obj.appendChild(div); success = div.parentNode == obj; } catch (e) { return false; } finally { try { obj.removeChild(div); } catch (e) { // Remove failed, not much we can do about that } } return success; } function isElement(obj) { return div && obj && obj.nodeType === 1 && isDOMNode(obj); } function isFunction(obj) { return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply); } function isReallyNaN(val) { return typeof val === "number" && isNaN(val); } function mirrorProperties(target, source) { for (var prop in source) { if (!hasOwn.call(target, prop)) { target[prop] = source[prop]; } } } function isRestorable(obj) { return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon; } // Cheap way to detect if we have ES5 support. var hasES5Support = "keys" in Object; function makeApi(sinon) { sinon.wrapMethod = function wrapMethod(object, property, method) { if (!object) { throw new TypeError("Should wrap property of object"); } if (typeof method != "function" && typeof method != "object") { throw new TypeError("Method wrapper should be a function or a property descriptor"); } function checkWrappedMethod(wrappedMethod) { if (!isFunction(wrappedMethod)) { error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + property + " as function"); } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) { error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); } else if (wrappedMethod.calledBefore) { var verb = !!wrappedMethod.returns ? "stubbed" : "spied on"; error = new TypeError("Attempted to wrap " + property + " which is already " + verb); } if (error) { if (wrappedMethod && wrappedMethod.stackTrace) { error.stack += "\n--------------\n" + wrappedMethod.stackTrace; } throw error; } } var error, wrappedMethod; // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem // when using hasOwn.call on objects from other frames. var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property); if (hasES5Support) { var methodDesc = (typeof method == "function") ? {value: method} : method, wrappedMethodDesc = sinon.getPropertyDescriptor(object, property), i; if (!wrappedMethodDesc) { error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + property + " as function"); } else if (wrappedMethodDesc.restore && wrappedMethodDesc.restore.sinon) { error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); } if (error) { if (wrappedMethodDesc && wrappedMethodDesc.stackTrace) { error.stack += "\n--------------\n" + wrappedMethodDesc.stackTrace; } throw error; } var types = sinon.objectKeys(methodDesc); for (i = 0; i < types.length; i++) { wrappedMethod = wrappedMethodDesc[types[i]]; checkWrappedMethod(wrappedMethod); } mirrorProperties(methodDesc, wrappedMethodDesc); for (i = 0; i < types.length; i++) { mirrorProperties(methodDesc[types[i]], wrappedMethodDesc[types[i]]); } Object.defineProperty(object, property, methodDesc); } else { wrappedMethod = object[property]; checkWrappedMethod(wrappedMethod); object[property] = method; method.displayName = property; } method.displayName = property; // Set up a stack trace which can be used later to find what line of // code the original method was created on. method.stackTrace = (new Error("Stack Trace for original")).stack; method.restore = function () { // For prototype properties try to reset by delete first. // If this fails (ex: localStorage on mobile safari) then force a reset // via direct assignment. if (!owned) { // In some cases `delete` may throw an error try { delete object[property]; } catch (e) {} // For native code functions `delete` fails without throwing an error // on Chrome < 43, PhantomJS, etc. } else if (hasES5Support) { Object.defineProperty(object, property, wrappedMethodDesc); } // Use strict equality comparison to check failures then force a reset // via direct assignment. if (object[property] === method) { object[property] = wrappedMethod; } }; method.restore.sinon = true; if (!hasES5Support) { mirrorProperties(method, wrappedMethod); } return method; }; sinon.create = function create(proto) { var F = function () {}; F.prototype = proto; return new F(); }; sinon.deepEqual = function deepEqual(a, b) { if (sinon.match && sinon.match.isMatcher(a)) { return a.test(b); } if (typeof a != "object" || typeof b != "object") { if (isReallyNaN(a) && isReallyNaN(b)) { return true; } else { return a === b; } } if (isElement(a) || isElement(b)) { return a === b; } if (a === b) { return true; } if ((a === null && b !== null) || (a !== null && b === null)) { return false; } if (a instanceof RegExp && b instanceof RegExp) { return (a.source === b.source) && (a.global === b.global) && (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline); } var aString = Object.prototype.toString.call(a); if (aString != Object.prototype.toString.call(b)) { return false; } if (aString == "[object Date]") { return a.valueOf() === b.valueOf(); } var prop, aLength = 0, bLength = 0; if (aString == "[object Array]" && a.length !== b.length) { return false; } for (prop in a) { aLength += 1; if (!(prop in b)) { return false; } if (!deepEqual(a[prop], b[prop])) { return false; } } for (prop in b) { bLength += 1; } return aLength == bLength; }; sinon.functionName = function functionName(func) { var name = func.displayName || func.name; // Use function decomposition as a last resort to get function // name. Does not rely on function decomposition to work - if it // doesn't debugging will be slightly less informative // (i.e. toString will say 'spy' rather than 'myFunc'). if (!name) { var matches = func.toString().match(/function ([^\s\(]+)/); name = matches && matches[1]; } return name; }; sinon.functionToString = function toString() { if (this.getCall && this.callCount) { var thisValue, prop, i = this.callCount; while (i--) { thisValue = this.getCall(i).thisValue; for (prop in thisValue) { if (thisValue[prop] === this) { return prop; } } } } return this.displayName || "sinon fake"; }; sinon.objectKeys = function objectKeys(obj) { if (obj !== Object(obj)) { throw new TypeError("sinon.objectKeys called on a non-object"); } var keys = []; var key; for (key in obj) { if (hasOwn.call(obj, key)) { keys.push(key); } } return keys; }; sinon.getPropertyDescriptor = function getPropertyDescriptor(object, property) { var proto = object, descriptor; while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) { proto = Object.getPrototypeOf(proto); } return descriptor; } sinon.getConfig = function (custom) { var config = {}; custom = custom || {}; var defaults = sinon.defaultConfig; for (var prop in defaults) { if (defaults.hasOwnProperty(prop)) { config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop]; } } return config; }; sinon.defaultConfig = { injectIntoThis: true, injectInto: null, properties: ["spy", "stub", "mock", "clock", "server", "requests"], useFakeTimers: true, useFakeServer: true }; sinon.timesInWords = function timesInWords(count) { return count == 1 && "once" || count == 2 && "twice" || count == 3 && "thrice" || (count || 0) + " times"; }; sinon.calledInOrder = function (spies) { for (var i = 1, l = spies.length; i < l; i++) { if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) { return false; } } return true; }; sinon.orderByFirstCall = function (spies) { return spies.sort(function (a, b) { // uuid, won't ever be equal var aCall = a.getCall(0); var bCall = b.getCall(0); var aId = aCall && aCall.callId || -1; var bId = bCall && bCall.callId || -1; return aId < bId ? -1 : 1; }); }; sinon.createStubInstance = function (constructor) { if (typeof constructor !== "function") { throw new TypeError("The constructor should be a function."); } return sinon.stub(sinon.create(constructor.prototype)); }; sinon.restore = function (object) { if (object !== null && typeof object === "object") { for (var prop in object) { if (isRestorable(object[prop])) { object[prop].restore(); } } } else if (isRestorable(object)) { object.restore(); } }; return sinon; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports) { makeApi(exports); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend util/core.js */ (function (sinon) { function makeApi(sinon) { // Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug var hasDontEnumBug = (function () { var obj = { constructor: function () { return "0"; }, toString: function () { return "1"; }, valueOf: function () { return "2"; }, toLocaleString: function () { return "3"; }, prototype: function () { return "4"; }, isPrototypeOf: function () { return "5"; }, propertyIsEnumerable: function () { return "6"; }, hasOwnProperty: function () { return "7"; }, length: function () { return "8"; }, unique: function () { return "9" } }; var result = []; for (var prop in obj) { result.push(obj[prop]()); } return result.join("") !== "0123456789"; })(); /* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will * override properties in previous sources. * * target - The Object to extend * sources - Objects to copy properties from. * * Returns the extended target */ function extend(target /*, sources */) { var sources = Array.prototype.slice.call(arguments, 1), source, i, prop; for (i = 0; i < sources.length; i++) { source = sources[i]; for (prop in source) { if (source.hasOwnProperty(prop)) { target[prop] = source[prop]; } } // Make sure we copy (own) toString method even when in JScript with DontEnum bug // See https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug if (hasDontEnumBug && source.hasOwnProperty("toString") && source.toString !== target.toString) { target.toString = source.toString; } } return target; }; sinon.extend = extend; return sinon.extend; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend util/core.js */ (function (sinon) { function makeApi(sinon) { function timesInWords(count) { switch (count) { case 1: return "once"; case 2: return "twice"; case 3: return "thrice"; default: return (count || 0) + " times"; } } sinon.timesInWords = timesInWords; return sinon.timesInWords; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend util/core.js */ /** * Format functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ (function (sinon, formatio) { function makeApi(sinon) { function typeOf(value) { if (value === null) { return "null"; } else if (value === undefined) { return "undefined"; } var string = Object.prototype.toString.call(value); return string.substring(8, string.length - 1).toLowerCase(); }; sinon.typeOf = typeOf; return sinon.typeOf; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }( (typeof sinon == "object" && sinon || null), (typeof formatio == "object" && formatio) )); /** * @depend util/core.js * @depend typeOf.js */ /*jslint eqeqeq: false, onevar: false, plusplus: false*/ /*global module, require, sinon*/ /** * Match functions * * @author Maximilian Antoni (mail@maxantoni.de) * @license BSD * * Copyright (c) 2012 Maximilian Antoni */ (function (sinon) { function makeApi(sinon) { function assertType(value, type, name) { var actual = sinon.typeOf(value); if (actual !== type) { throw new TypeError("Expected type of " + name + " to be " + type + ", but was " + actual); } } var matcher = { toString: function () { return this.message; } }; function isMatcher(object) { return matcher.isPrototypeOf(object); } function matchObject(expectation, actual) { if (actual === null || actual === undefined) { return false; } for (var key in expectation) { if (expectation.hasOwnProperty(key)) { var exp = expectation[key]; var act = actual[key]; if (match.isMatcher(exp)) { if (!exp.test(act)) { return false; } } else if (sinon.typeOf(exp) === "object") { if (!matchObject(exp, act)) { return false; } } else if (!sinon.deepEqual(exp, act)) { return false; } } } return true; } matcher.or = function (m2) { if (!arguments.length) { throw new TypeError("Matcher expected"); } else if (!isMatcher(m2)) { m2 = match(m2); } var m1 = this; var or = sinon.create(matcher); or.test = function (actual) { return m1.test(actual) || m2.test(actual); }; or.message = m1.message + ".or(" + m2.message + ")"; return or; }; matcher.and = function (m2) { if (!arguments.length) { throw new TypeError("Matcher expected"); } else if (!isMatcher(m2)) { m2 = match(m2); } var m1 = this; var and = sinon.create(matcher); and.test = function (actual) { return m1.test(actual) && m2.test(actual); }; and.message = m1.message + ".and(" + m2.message + ")"; return and; }; var match = function (expectation, message) { var m = sinon.create(matcher); var type = sinon.typeOf(expectation); switch (type) { case "object": if (typeof expectation.test === "function") { m.test = function (actual) { return expectation.test(actual) === true; }; m.message = "match(" + sinon.functionName(expectation.test) + ")"; return m; } var str = []; for (var key in expectation) { if (expectation.hasOwnProperty(key)) { str.push(key + ": " + expectation[key]); } } m.test = function (actual) { return matchObject(expectation, actual); }; m.message = "match(" + str.join(", ") + ")"; break; case "number": m.test = function (actual) { return expectation == actual; }; break; case "string": m.test = function (actual) { if (typeof actual !== "string") { return false; } return actual.indexOf(expectation) !== -1; }; m.message = "match(\"" + expectation + "\")"; break; case "regexp": m.test = function (actual) { if (typeof actual !== "string") { return false; } return expectation.test(actual); }; break; case "function": m.test = expectation; if (message) { m.message = message; } else { m.message = "match(" + sinon.functionName(expectation) + ")"; } break; default: m.test = function (actual) { return sinon.deepEqual(expectation, actual); }; } if (!m.message) { m.message = "match(" + expectation + ")"; } return m; }; match.isMatcher = isMatcher; match.any = match(function () { return true; }, "any"); match.defined = match(function (actual) { return actual !== null && actual !== undefined; }, "defined"); match.truthy = match(function (actual) { return !!actual; }, "truthy"); match.falsy = match(function (actual) { return !actual; }, "falsy"); match.same = function (expectation) { return match(function (actual) { return expectation === actual; }, "same(" + expectation + ")"); }; match.typeOf = function (type) { assertType(type, "string", "type"); return match(function (actual) { return sinon.typeOf(actual) === type; }, "typeOf(\"" + type + "\")"); }; match.instanceOf = function (type) { assertType(type, "function", "type"); return match(function (actual) { return actual instanceof type; }, "instanceOf(" + sinon.functionName(type) + ")"); }; function createPropertyMatcher(propertyTest, messagePrefix) { return function (property, value) { assertType(property, "string", "property"); var onlyProperty = arguments.length === 1; var message = messagePrefix + "(\"" + property + "\""; if (!onlyProperty) { message += ", " + value; } message += ")"; return match(function (actual) { if (actual === undefined || actual === null || !propertyTest(actual, property)) { return false; } return onlyProperty || sinon.deepEqual(value, actual[property]); }, message); }; } match.has = createPropertyMatcher(function (actual, property) { if (typeof actual === "object") { return property in actual; } return actual[property] !== undefined; }, "has"); match.hasOwn = createPropertyMatcher(function (actual, property) { return actual.hasOwnProperty(property); }, "hasOwn"); match.bool = match.typeOf("boolean"); match.number = match.typeOf("number"); match.string = match.typeOf("string"); match.object = match.typeOf("object"); match.func = match.typeOf("function"); match.array = match.typeOf("array"); match.regexp = match.typeOf("regexp"); match.date = match.typeOf("date"); sinon.match = match; return match; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./typeOf"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend util/core.js */ /** * Format functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ (function (sinon, formatio) { function makeApi(sinon) { function valueFormatter(value) { return "" + value; } function getFormatioFormatter() { var formatter = formatio.configure({ quoteStrings: false, limitChildrenCount: 250 }); function format() { return formatter.ascii.apply(formatter, arguments); }; return format; } function getNodeFormatter(value) { function format(value) { return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value; }; try { var util = require("util"); } catch (e) { /* Node, but no util module - would be very old, but better safe than sorry */ } return util ? format : valueFormatter; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function", formatter; if (isNode) { try { formatio = require("formatio"); } catch (e) {} } if (formatio) { formatter = getFormatioFormatter() } else if (isNode) { formatter = getNodeFormatter(); } else { formatter = valueFormatter; } sinon.format = formatter; return sinon.format; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }( (typeof sinon == "object" && sinon || null), (typeof formatio == "object" && formatio) )); /** * @depend util/core.js * @depend match.js * @depend format.js */ /** * Spy calls * * @author Christian Johansen (christian@cjohansen.no) * @author Maximilian Antoni (mail@maxantoni.de) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen * Copyright (c) 2013 Maximilian Antoni */ (function (sinon) { function makeApi(sinon) { function throwYieldError(proxy, text, args) { var msg = sinon.functionName(proxy) + text; if (args.length) { msg += " Received [" + slice.call(args).join(", ") + "]"; } throw new Error(msg); } var slice = Array.prototype.slice; var callProto = { calledOn: function calledOn(thisValue) { if (sinon.match && sinon.match.isMatcher(thisValue)) { return thisValue.test(this.thisValue); } return this.thisValue === thisValue; }, calledWith: function calledWith() { var l = arguments.length; if (l > this.args.length) { return false; } for (var i = 0; i < l; i += 1) { if (!sinon.deepEqual(arguments[i], this.args[i])) { return false; } } return true; }, calledWithMatch: function calledWithMatch() { var l = arguments.length; if (l > this.args.length) { return false; } for (var i = 0; i < l; i += 1) { var actual = this.args[i]; var expectation = arguments[i]; if (!sinon.match || !sinon.match(expectation).test(actual)) { return false; } } return true; }, calledWithExactly: function calledWithExactly() { return arguments.length == this.args.length && this.calledWith.apply(this, arguments); }, notCalledWith: function notCalledWith() { return !this.calledWith.apply(this, arguments); }, notCalledWithMatch: function notCalledWithMatch() { return !this.calledWithMatch.apply(this, arguments); }, returned: function returned(value) { return sinon.deepEqual(value, this.returnValue); }, threw: function threw(error) { if (typeof error === "undefined" || !this.exception) { return !!this.exception; } return this.exception === error || this.exception.name === error; }, calledWithNew: function calledWithNew() { return this.proxy.prototype && this.thisValue instanceof this.proxy; }, calledBefore: function (other) { return this.callId < other.callId; }, calledAfter: function (other) { return this.callId > other.callId; }, callArg: function (pos) { this.args[pos](); }, callArgOn: function (pos, thisValue) { this.args[pos].apply(thisValue); }, callArgWith: function (pos) { this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1))); }, callArgOnWith: function (pos, thisValue) { var args = slice.call(arguments, 2); this.args[pos].apply(thisValue, args); }, yield: function () { this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0))); }, yieldOn: function (thisValue) { var args = this.args; for (var i = 0, l = args.length; i < l; ++i) { if (typeof args[i] === "function") { args[i].apply(thisValue, slice.call(arguments, 1)); return; } } throwYieldError(this.proxy, " cannot yield since no callback was passed.", args); }, yieldTo: function (prop) { this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1))); }, yieldToOn: function (prop, thisValue) { var args = this.args; for (var i = 0, l = args.length; i < l; ++i) { if (args[i] && typeof args[i][prop] === "function") { args[i][prop].apply(thisValue, slice.call(arguments, 2)); return; } } throwYieldError(this.proxy, " cannot yield to '" + prop + "' since no callback was passed.", args); }, toString: function () { var callStr = this.proxy.toString() + "("; var args = []; for (var i = 0, l = this.args.length; i < l; ++i) { args.push(sinon.format(this.args[i])); } callStr = callStr + args.join(", ") + ")"; if (typeof this.returnValue != "undefined") { callStr += " => " + sinon.format(this.returnValue); } if (this.exception) { callStr += " !" + this.exception.name; if (this.exception.message) { callStr += "(" + this.exception.message + ")"; } } return callStr; } }; callProto.invokeCallback = callProto.yield; function createSpyCall(spy, thisValue, args, returnValue, exception, id) { if (typeof id !== "number") { throw new TypeError("Call id is not a number"); } var proxyCall = sinon.create(callProto); proxyCall.proxy = spy; proxyCall.thisValue = thisValue; proxyCall.args = args; proxyCall.returnValue = returnValue; proxyCall.exception = exception; proxyCall.callId = id; return proxyCall; } createSpyCall.toString = callProto.toString; // used by mocks sinon.spyCall = createSpyCall; return createSpyCall; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./match"); require("./format"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend times_in_words.js * @depend util/core.js * @depend extend.js * @depend call.js * @depend format.js */ /** * Spy functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinon) { function makeApi(sinon) { var push = Array.prototype.push; var slice = Array.prototype.slice; var callId = 0; function spy(object, property, types) { if (!property && typeof object == "function") { return spy.create(object); } if (!object && !property) { return spy.create(function () { }); } if (types) { var methodDesc = sinon.getPropertyDescriptor(object, property); for (var i = 0; i < types.length; i++) { methodDesc[types[i]] = spy.create(methodDesc[types[i]]); } return sinon.wrapMethod(object, property, methodDesc); } else { var method = object[property]; return sinon.wrapMethod(object, property, spy.create(method)); } } function matchingFake(fakes, args, strict) { if (!fakes) { return; } for (var i = 0, l = fakes.length; i < l; i++) { if (fakes[i].matches(args, strict)) { return fakes[i]; } } } function incrementCallCount() { this.called = true; this.callCount += 1; this.notCalled = false; this.calledOnce = this.callCount == 1; this.calledTwice = this.callCount == 2; this.calledThrice = this.callCount == 3; } function createCallProperties() { this.firstCall = this.getCall(0); this.secondCall = this.getCall(1); this.thirdCall = this.getCall(2); this.lastCall = this.getCall(this.callCount - 1); } var vars = "a,b,c,d,e,f,g,h,i,j,k,l"; function createProxy(func, proxyLength) { // Retain the function length: var p; if (proxyLength) { eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) + ") { return p.invoke(func, this, slice.call(arguments)); });"); } else { p = function proxy() { return p.invoke(func, this, slice.call(arguments)); }; } p.isSinonProxy = true; return p; } var uuid = 0; // Public API var spyApi = { reset: function () { if (this.invoking) { var err = new Error("Cannot reset Sinon function while invoking it. " + "Move the call to .reset outside of the callback."); err.name = "InvalidResetException"; throw err; } this.called = false; this.notCalled = true; this.calledOnce = false; this.calledTwice = false; this.calledThrice = false; this.callCount = 0; this.firstCall = null; this.secondCall = null; this.thirdCall = null; this.lastCall = null; this.args = []; this.returnValues = []; this.thisValues = []; this.exceptions = []; this.callIds = []; if (this.fakes) { for (var i = 0; i < this.fakes.length; i++) { this.fakes[i].reset(); } } return this; }, create: function create(func, spyLength) { var name; if (typeof func != "function") { func = function () { }; } else { name = sinon.functionName(func); } if (!spyLength) { spyLength = func.length; } var proxy = createProxy(func, spyLength); sinon.extend(proxy, spy); delete proxy.create; sinon.extend(proxy, func); proxy.reset(); proxy.prototype = func.prototype; proxy.displayName = name || "spy"; proxy.toString = sinon.functionToString; proxy.instantiateFake = sinon.spy.create; proxy.id = "spy#" + uuid++; return proxy; }, invoke: function invoke(func, thisValue, args) { var matching = matchingFake(this.fakes, args); var exception, returnValue; incrementCallCount.call(this); push.call(this.thisValues, thisValue); push.call(this.args, args); push.call(this.callIds, callId++); // Make call properties available from within the spied function: createCallProperties.call(this); try { this.invoking = true; if (matching) { returnValue = matching.invoke(func, thisValue, args); } else { returnValue = (this.func || func).apply(thisValue, args); } var thisCall = this.getCall(this.callCount - 1); if (thisCall.calledWithNew() && typeof returnValue !== "object") { returnValue = thisValue; } } catch (e) { exception = e; } finally { delete this.invoking; } push.call(this.exceptions, exception); push.call(this.returnValues, returnValue); // Make return value and exception available in the calls: createCallProperties.call(this); if (exception !== undefined) { throw exception; } return returnValue; }, named: function named(name) { this.displayName = name; return this; }, getCall: function getCall(i) { if (i < 0 || i >= this.callCount) { return null; } return sinon.spyCall(this, this.thisValues[i], this.args[i], this.returnValues[i], this.exceptions[i], this.callIds[i]); }, getCalls: function () { var calls = []; var i; for (i = 0; i < this.callCount; i++) { calls.push(this.getCall(i)); } return calls; }, calledBefore: function calledBefore(spyFn) { if (!this.called) { return false; } if (!spyFn.called) { return true; } return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; }, calledAfter: function calledAfter(spyFn) { if (!this.called || !spyFn.called) { return false; } return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; }, withArgs: function () { var args = slice.call(arguments); if (this.fakes) { var match = matchingFake(this.fakes, args, true); if (match) { return match; } } else { this.fakes = []; } var original = this; var fake = this.instantiateFake(); fake.matchingAguments = args; fake.parent = this; push.call(this.fakes, fake); fake.withArgs = function () { return original.withArgs.apply(original, arguments); }; for (var i = 0; i < this.args.length; i++) { if (fake.matches(this.args[i])) { incrementCallCount.call(fake); push.call(fake.thisValues, this.thisValues[i]); push.call(fake.args, this.args[i]); push.call(fake.returnValues, this.returnValues[i]); push.call(fake.exceptions, this.exceptions[i]); push.call(fake.callIds, this.callIds[i]); } } createCallProperties.call(fake); return fake; }, matches: function (args, strict) { var margs = this.matchingAguments; if (margs.length <= args.length && sinon.deepEqual(margs, args.slice(0, margs.length))) { return !strict || margs.length == args.length; } }, printf: function (format) { var spy = this; var args = slice.call(arguments, 1); var formatter; return (format || "").replace(/%(.)/g, function (match, specifyer) { formatter = spyApi.formatters[specifyer]; if (typeof formatter == "function") { return formatter.call(null, spy, args); } else if (!isNaN(parseInt(specifyer, 10))) { return sinon.format(args[specifyer - 1]); } return "%" + specifyer; }); } }; function delegateToCalls(method, matchAny, actual, notCalled) { spyApi[method] = function () { if (!this.called) { if (notCalled) { return notCalled.apply(this, arguments); } return false; } var currentCall; var matches = 0; for (var i = 0, l = this.callCount; i < l; i += 1) { currentCall = this.getCall(i); if (currentCall[actual || method].apply(currentCall, arguments)) { matches += 1; if (matchAny) { return true; } } } return matches === this.callCount; }; } delegateToCalls("calledOn", true); delegateToCalls("alwaysCalledOn", false, "calledOn"); delegateToCalls("calledWith", true); delegateToCalls("calledWithMatch", true); delegateToCalls("alwaysCalledWith", false, "calledWith"); delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch"); delegateToCalls("calledWithExactly", true); delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly"); delegateToCalls("neverCalledWith", false, "notCalledWith", function () { return true; }); delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", function () { return true; }); delegateToCalls("threw", true); delegateToCalls("alwaysThrew", false, "threw"); delegateToCalls("returned", true); delegateToCalls("alwaysReturned", false, "returned"); delegateToCalls("calledWithNew", true); delegateToCalls("alwaysCalledWithNew", false, "calledWithNew"); delegateToCalls("callArg", false, "callArgWith", function () { throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); }); spyApi.callArgWith = spyApi.callArg; delegateToCalls("callArgOn", false, "callArgOnWith", function () { throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); }); spyApi.callArgOnWith = spyApi.callArgOn; delegateToCalls("yield", false, "yield", function () { throw new Error(this.toString() + " cannot yield since it was not yet invoked."); }); // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. spyApi.invokeCallback = spyApi.yield; delegateToCalls("yieldOn", false, "yieldOn", function () { throw new Error(this.toString() + " cannot yield since it was not yet invoked."); }); delegateToCalls("yieldTo", false, "yieldTo", function (property) { throw new Error(this.toString() + " cannot yield to '" + property + "' since it was not yet invoked."); }); delegateToCalls("yieldToOn", false, "yieldToOn", function (property) { throw new Error(this.toString() + " cannot yield to '" + property + "' since it was not yet invoked."); }); spyApi.formatters = { c: function (spy) { return sinon.timesInWords(spy.callCount); }, n: function (spy) { return spy.toString(); }, C: function (spy) { var calls = []; for (var i = 0, l = spy.callCount; i < l; ++i) { var stringifiedCall = " " + spy.getCall(i).toString(); if (/\n/.test(calls[i - 1])) { stringifiedCall = "\n" + stringifiedCall; } push.call(calls, stringifiedCall); } return calls.length > 0 ? "\n" + calls.join("\n") : ""; }, t: function (spy) { var objects = []; for (var i = 0, l = spy.callCount; i < l; ++i) { push.call(objects, sinon.format(spy.thisValues[i])); } return objects.join(", "); }, "*": function (spy, args) { var formatted = []; for (var i = 0, l = args.length; i < l; ++i) { push.call(formatted, sinon.format(args[i])); } return formatted.join(", "); } }; sinon.extend(spy, spyApi); spy.spyCall = sinon.spyCall; sinon.spy = spy; return spy; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./call"); require("./extend"); require("./times_in_words"); require("./format"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend util/core.js * @depend extend.js */ /** * Stub behavior * * @author Christian Johansen (christian@cjohansen.no) * @author Tim Fischbach (mail@timfischbach.de) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinon) { var slice = Array.prototype.slice; var join = Array.prototype.join; var useLeftMostCallback = -1; var useRightMostCallback = -2; var nextTick = (function () { if (typeof process === "object" && typeof process.nextTick === "function") { return process.nextTick; } else if (typeof setImmediate === "function") { return setImmediate; } else { return function (callback) { setTimeout(callback, 0); }; } })(); function throwsException(error, message) { if (typeof error == "string") { this.exception = new Error(message || ""); this.exception.name = error; } else if (!error) { this.exception = new Error("Error"); } else { this.exception = error; } return this; } function getCallback(behavior, args) { var callArgAt = behavior.callArgAt; if (callArgAt >= 0) { return args[callArgAt]; } var argumentList; if (callArgAt === useLeftMostCallback) { argumentList = args; } if (callArgAt === useRightMostCallback) { argumentList = slice.call(args).reverse(); } var callArgProp = behavior.callArgProp; for (var i = 0, l = argumentList.length; i < l; ++i) { if (!callArgProp && typeof argumentList[i] == "function") { return argumentList[i]; } if (callArgProp && argumentList[i] && typeof argumentList[i][callArgProp] == "function") { return argumentList[i][callArgProp]; } } return null; } function makeApi(sinon) { function getCallbackError(behavior, func, args) { if (behavior.callArgAt < 0) { var msg; if (behavior.callArgProp) { msg = sinon.functionName(behavior.stub) + " expected to yield to '" + behavior.callArgProp + "', but no object with such a property was passed."; } else { msg = sinon.functionName(behavior.stub) + " expected to yield, but no callback was passed."; } if (args.length > 0) { msg += " Received [" + join.call(args, ", ") + "]"; } return msg; } return "argument at index " + behavior.callArgAt + " is not a function: " + func; } function callCallback(behavior, args) { if (typeof behavior.callArgAt == "number") { var func = getCallback(behavior, args); if (typeof func != "function") { throw new TypeError(getCallbackError(behavior, func, args)); } if (behavior.callbackAsync) { nextTick(function () { func.apply(behavior.callbackContext, behavior.callbackArguments); }); } else { func.apply(behavior.callbackContext, behavior.callbackArguments); } } } var proto = { create: function create(stub) { var behavior = sinon.extend({}, sinon.behavior); delete behavior.create; behavior.stub = stub; return behavior; }, isPresent: function isPresent() { return (typeof this.callArgAt == "number" || this.exception || typeof this.returnArgAt == "number" || this.returnThis || this.returnValueDefined); }, invoke: function invoke(context, args) { callCallback(this, args); if (this.exception) { throw this.exception; } else if (typeof this.returnArgAt == "number") { return args[this.returnArgAt]; } else if (this.returnThis) { return context; } return this.returnValue; }, onCall: function onCall(index) { return this.stub.onCall(index); }, onFirstCall: function onFirstCall() { return this.stub.onFirstCall(); }, onSecondCall: function onSecondCall() { return this.stub.onSecondCall(); }, onThirdCall: function onThirdCall() { return this.stub.onThirdCall(); }, withArgs: function withArgs(/* arguments */) { throw new Error("Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" is not supported. " + "Use \"stub.withArgs(...).onCall(...)\" to define sequential behavior for calls with certain arguments."); }, callsArg: function callsArg(pos) { if (typeof pos != "number") { throw new TypeError("argument index is not number"); } this.callArgAt = pos; this.callbackArguments = []; this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, callsArgOn: function callsArgOn(pos, context) { if (typeof pos != "number") { throw new TypeError("argument index is not number"); } if (typeof context != "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = pos; this.callbackArguments = []; this.callbackContext = context; this.callArgProp = undefined; this.callbackAsync = false; return this; }, callsArgWith: function callsArgWith(pos) { if (typeof pos != "number") { throw new TypeError("argument index is not number"); } this.callArgAt = pos; this.callbackArguments = slice.call(arguments, 1); this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, callsArgOnWith: function callsArgWith(pos, context) { if (typeof pos != "number") { throw new TypeError("argument index is not number"); } if (typeof context != "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = pos; this.callbackArguments = slice.call(arguments, 2); this.callbackContext = context; this.callArgProp = undefined; this.callbackAsync = false; return this; }, yields: function () { this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 0); this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, yieldsRight: function () { this.callArgAt = useRightMostCallback; this.callbackArguments = slice.call(arguments, 0); this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, yieldsOn: function (context) { if (typeof context != "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 1); this.callbackContext = context; this.callArgProp = undefined; this.callbackAsync = false; return this; }, yieldsTo: function (prop) { this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 1); this.callbackContext = undefined; this.callArgProp = prop; this.callbackAsync = false; return this; }, yieldsToOn: function (prop, context) { if (typeof context != "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 2); this.callbackContext = context; this.callArgProp = prop; this.callbackAsync = false; return this; }, throws: throwsException, throwsException: throwsException, returns: function returns(value) { this.returnValue = value; this.returnValueDefined = true; return this; }, returnsArg: function returnsArg(pos) { if (typeof pos != "number") { throw new TypeError("argument index is not number"); } this.returnArgAt = pos; return this; }, returnsThis: function returnsThis() { this.returnThis = true; return this; } }; // create asynchronous versions of callsArg* and yields* methods for (var method in proto) { // need to avoid creating anotherasync versions of the newly added async methods if (proto.hasOwnProperty(method) && method.match(/^(callsArg|yields)/) && !method.match(/Async/)) { proto[method + "Async"] = (function (syncFnName) { return function () { var result = this[syncFnName].apply(this, arguments); this.callbackAsync = true; return result; }; })(method); } } sinon.behavior = proto; return proto; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./extend"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend util/core.js * @depend extend.js * @depend spy.js * @depend behavior.js */ /** * Stub functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinon) { function makeApi(sinon) { function stub(object, property, func) { if (!!func && typeof func != "function" && typeof func != "object") { throw new TypeError("Custom stub should be a function or a property descriptor"); } var wrapper; if (func) { if (typeof func == "function") { wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; } else { wrapper = func; if (sinon.spy && sinon.spy.create) { var types = sinon.objectKeys(wrapper); for (var i = 0; i < types.length; i++) { wrapper[types[i]] = sinon.spy.create(wrapper[types[i]]); } } } } else { var stubLength = 0; if (typeof object == "object" && typeof object[property] == "function") { stubLength = object[property].length; } wrapper = stub.create(stubLength); } if (!object && typeof property === "undefined") { return sinon.stub.create(); } if (typeof property === "undefined" && typeof object == "object") { for (var prop in object) { if (typeof sinon.getPropertyDescriptor(object, prop).value === "function") { stub(object, prop); } } return object; } return sinon.wrapMethod(object, property, wrapper); } function getDefaultBehavior(stub) { return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub); } function getParentBehaviour(stub) { return (stub.parent && getCurrentBehavior(stub.parent)); } function getCurrentBehavior(stub) { var behavior = stub.behaviors[stub.callCount - 1]; return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub); } var uuid = 0; var proto = { create: function create(stubLength) { var functionStub = function () { return getCurrentBehavior(functionStub).invoke(this, arguments); }; functionStub.id = "stub#" + uuid++; var orig = functionStub; functionStub = sinon.spy.create(functionStub, stubLength); functionStub.func = orig; sinon.extend(functionStub, stub); functionStub.instantiateFake = sinon.stub.create; functionStub.displayName = "stub"; functionStub.toString = sinon.functionToString; functionStub.defaultBehavior = null; functionStub.behaviors = []; return functionStub; }, resetBehavior: function () { var i; this.defaultBehavior = null; this.behaviors = []; delete this.returnValue; delete this.returnArgAt; this.returnThis = false; if (this.fakes) { for (i = 0; i < this.fakes.length; i++) { this.fakes[i].resetBehavior(); } } }, onCall: function onCall(index) { if (!this.behaviors[index]) { this.behaviors[index] = sinon.behavior.create(this); } return this.behaviors[index]; }, onFirstCall: function onFirstCall() { return this.onCall(0); }, onSecondCall: function onSecondCall() { return this.onCall(1); }, onThirdCall: function onThirdCall() { return this.onCall(2); } }; for (var method in sinon.behavior) { if (sinon.behavior.hasOwnProperty(method) && !proto.hasOwnProperty(method) && method != "create" && method != "withArgs" && method != "invoke") { proto[method] = (function (behaviorMethod) { return function () { this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); return this; }; }(method)); } } sinon.extend(stub, proto); sinon.stub = stub; return stub; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./behavior"); require("./spy"); require("./extend"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend times_in_words.js * @depend util/core.js * @depend call.js * @depend extend.js * @depend match.js * @depend spy.js * @depend stub.js * @depend format.js */ /** * Mock functions. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinon) { function makeApi(sinon) { var push = [].push; var match = sinon.match; function mock(object) { // if (typeof console !== undefined && console.warn) { // console.warn("mock will be removed from Sinon.JS v2.0"); // } if (!object) { return sinon.expectation.create("Anonymous mock"); } return mock.create(object); } function each(collection, callback) { if (!collection) { return; } for (var i = 0, l = collection.length; i < l; i += 1) { callback(collection[i]); } } sinon.extend(mock, { create: function create(object) { if (!object) { throw new TypeError("object is null"); } var mockObject = sinon.extend({}, mock); mockObject.object = object; delete mockObject.create; return mockObject; }, expects: function expects(method) { if (!method) { throw new TypeError("method is falsy"); } if (!this.expectations) { this.expectations = {}; this.proxies = []; } if (!this.expectations[method]) { this.expectations[method] = []; var mockObject = this; sinon.wrapMethod(this.object, method, function () { return mockObject.invokeMethod(method, this, arguments); }); push.call(this.proxies, method); } var expectation = sinon.expectation.create(method); push.call(this.expectations[method], expectation); return expectation; }, restore: function restore() { var object = this.object; each(this.proxies, function (proxy) { if (typeof object[proxy].restore == "function") { object[proxy].restore(); } }); }, verify: function verify() { var expectations = this.expectations || {}; var messages = [], met = []; each(this.proxies, function (proxy) { each(expectations[proxy], function (expectation) { if (!expectation.met()) { push.call(messages, expectation.toString()); } else { push.call(met, expectation.toString()); } }); }); this.restore(); if (messages.length > 0) { sinon.expectation.fail(messages.concat(met).join("\n")); } else if (met.length > 0) { sinon.expectation.pass(messages.concat(met).join("\n")); } return true; }, invokeMethod: function invokeMethod(method, thisValue, args) { var expectations = this.expectations && this.expectations[method]; var length = expectations && expectations.length || 0, i; for (i = 0; i < length; i += 1) { if (!expectations[i].met() && expectations[i].allowsCall(thisValue, args)) { return expectations[i].apply(thisValue, args); } } var messages = [], available, exhausted = 0; for (i = 0; i < length; i += 1) { if (expectations[i].allowsCall(thisValue, args)) { available = available || expectations[i]; } else { exhausted += 1; } push.call(messages, " " + expectations[i].toString()); } if (exhausted === 0) { return available.apply(thisValue, args); } messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ proxy: method, args: args })); sinon.expectation.fail(messages.join("\n")); } }); var times = sinon.timesInWords; var slice = Array.prototype.slice; function callCountInWords(callCount) { if (callCount == 0) { return "never called"; } else { return "called " + times(callCount); } } function expectedCallCountInWords(expectation) { var min = expectation.minCalls; var max = expectation.maxCalls; if (typeof min == "number" && typeof max == "number") { var str = times(min); if (min != max) { str = "at least " + str + " and at most " + times(max); } return str; } if (typeof min == "number") { return "at least " + times(min); } return "at most " + times(max); } function receivedMinCalls(expectation) { var hasMinLimit = typeof expectation.minCalls == "number"; return !hasMinLimit || expectation.callCount >= expectation.minCalls; } function receivedMaxCalls(expectation) { if (typeof expectation.maxCalls != "number") { return false; } return expectation.callCount == expectation.maxCalls; } function verifyMatcher(possibleMatcher, arg) { if (match && match.isMatcher(possibleMatcher)) { return possibleMatcher.test(arg); } else { return true; } } sinon.expectation = { minCalls: 1, maxCalls: 1, create: function create(methodName) { var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); delete expectation.create; expectation.method = methodName; return expectation; }, invoke: function invoke(func, thisValue, args) { this.verifyCallAllowed(thisValue, args); return sinon.spy.invoke.apply(this, arguments); }, atLeast: function atLeast(num) { if (typeof num != "number") { throw new TypeError("'" + num + "' is not number"); } if (!this.limitsSet) { this.maxCalls = null; this.limitsSet = true; } this.minCalls = num; return this; }, atMost: function atMost(num) { if (typeof num != "number") { throw new TypeError("'" + num + "' is not number"); } if (!this.limitsSet) { this.minCalls = null; this.limitsSet = true; } this.maxCalls = num; return this; }, never: function never() { return this.exactly(0); }, once: function once() { return this.exactly(1); }, twice: function twice() { return this.exactly(2); }, thrice: function thrice() { return this.exactly(3); }, exactly: function exactly(num) { if (typeof num != "number") { throw new TypeError("'" + num + "' is not a number"); } this.atLeast(num); return this.atMost(num); }, met: function met() { return !this.failed && receivedMinCalls(this); }, verifyCallAllowed: function verifyCallAllowed(thisValue, args) { if (receivedMaxCalls(this)) { this.failed = true; sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); } if ("expectedThis" in this && this.expectedThis !== thisValue) { sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + this.expectedThis); } if (!("expectedArguments" in this)) { return; } if (!args) { sinon.expectation.fail(this.method + " received no arguments, expected " + sinon.format(this.expectedArguments)); } if (args.length < this.expectedArguments.length) { sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) + "), expected " + sinon.format(this.expectedArguments)); } if (this.expectsExactArgCount && args.length != this.expectedArguments.length) { sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + "), expected " + sinon.format(this.expectedArguments)); } for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { if (!verifyMatcher(this.expectedArguments[i], args[i])) { sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + ", didn't match " + this.expectedArguments.toString()); } if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + ", expected " + sinon.format(this.expectedArguments)); } } }, allowsCall: function allowsCall(thisValue, args) { if (this.met() && receivedMaxCalls(this)) { return false; } if ("expectedThis" in this && this.expectedThis !== thisValue) { return false; } if (!("expectedArguments" in this)) { return true; } args = args || []; if (args.length < this.expectedArguments.length) { return false; } if (this.expectsExactArgCount && args.length != this.expectedArguments.length) { return false; } for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { if (!verifyMatcher(this.expectedArguments[i], args[i])) { return false; } if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { return false; } } return true; }, withArgs: function withArgs() { this.expectedArguments = slice.call(arguments); return this; }, withExactArgs: function withExactArgs() { this.withArgs.apply(this, arguments); this.expectsExactArgCount = true; return this; }, on: function on(thisValue) { this.expectedThis = thisValue; return this; }, toString: function () { var args = (this.expectedArguments || []).slice(); if (!this.expectsExactArgCount) { push.call(args, "[...]"); } var callStr = sinon.spyCall.toString.call({ proxy: this.method || "anonymous mock expectation", args: args }); var message = callStr.replace(", [...", "[, ...") + " " + expectedCallCountInWords(this); if (this.met()) { return "Expectation met: " + message; } return "Expected " + message + " (" + callCountInWords(this.callCount) + ")"; }, verify: function verify() { if (!this.met()) { sinon.expectation.fail(this.toString()); } else { sinon.expectation.pass(this.toString()); } return true; }, pass: function pass(message) { sinon.assert.pass(message); }, fail: function fail(message) { var exception = new Error(message); exception.name = "ExpectationError"; throw exception; } }; sinon.mock = mock; return mock; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./times_in_words"); require("./call"); require("./extend"); require("./match"); require("./spy"); require("./stub"); require("./format"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend util/core.js * @depend spy.js * @depend stub.js * @depend mock.js */ /** * Collections of stubs, spies and mocks. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinon) { var push = [].push; var hasOwnProperty = Object.prototype.hasOwnProperty; function getFakes(fakeCollection) { if (!fakeCollection.fakes) { fakeCollection.fakes = []; } return fakeCollection.fakes; } function each(fakeCollection, method) { var fakes = getFakes(fakeCollection); for (var i = 0, l = fakes.length; i < l; i += 1) { if (typeof fakes[i][method] == "function") { fakes[i][method](); } } } function compact(fakeCollection) { var fakes = getFakes(fakeCollection); var i = 0; while (i < fakes.length) { fakes.splice(i, 1); } } function makeApi(sinon) { var collection = { verify: function resolve() { each(this, "verify"); }, restore: function restore() { each(this, "restore"); compact(this); }, reset: function restore() { each(this, "reset"); }, verifyAndRestore: function verifyAndRestore() { var exception; try { this.verify(); } catch (e) { exception = e; } this.restore(); if (exception) { throw exception; } }, add: function add(fake) { push.call(getFakes(this), fake); return fake; }, spy: function spy() { return this.add(sinon.spy.apply(sinon, arguments)); }, stub: function stub(object, property, value) { if (property) { var original = object[property]; if (typeof original != "function") { if (!hasOwnProperty.call(object, property)) { throw new TypeError("Cannot stub non-existent own property " + property); } object[property] = value; return this.add({ restore: function () { object[property] = original; } }); } } if (!property && !!object && typeof object == "object") { var stubbedObj = sinon.stub.apply(sinon, arguments); for (var prop in stubbedObj) { if (typeof stubbedObj[prop] === "function") { this.add(stubbedObj[prop]); } } return stubbedObj; } return this.add(sinon.stub.apply(sinon, arguments)); }, mock: function mock() { return this.add(sinon.mock.apply(sinon, arguments)); }, inject: function inject(obj) { var col = this; obj.spy = function () { return col.spy.apply(col, arguments); }; obj.stub = function () { return col.stub.apply(col, arguments); }; obj.mock = function () { return col.mock.apply(col, arguments); }; return obj; } }; sinon.collection = collection; return collection; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./mock"); require("./spy"); require("./stub"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /*global lolex */ /** * Fake timer API * setTimeout * setInterval * clearTimeout * clearInterval * tick * reset * Date * * Inspired by jsUnitMockTimeOut from JsUnit * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ if (typeof sinon == "undefined") { var sinon = {}; } (function (global) { function makeApi(sinon, lol) { var llx = typeof lolex !== "undefined" ? lolex : lol; sinon.useFakeTimers = function () { var now, methods = Array.prototype.slice.call(arguments); if (typeof methods[0] === "string") { now = 0; } else { now = methods.shift(); } var clock = llx.install(now || 0, methods); clock.restore = clock.uninstall; return clock; }; sinon.clock = { create: function (now) { return llx.createClock(now); } }; sinon.timers = { setTimeout: setTimeout, clearTimeout: clearTimeout, setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined), setInterval: setInterval, clearInterval: clearInterval, Date: Date }; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, epxorts, module, lolex) { var sinon = require("./core"); makeApi(sinon, lolex); module.exports = sinon; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module, require("lolex")); } else { makeApi(sinon); } }(typeof global != "undefined" && typeof global !== "function" ? global : this)); /** * Minimal Event interface implementation * * Original implementation by Sven Fuchs: https://gist.github.com/995028 * Modifications and tests by Christian Johansen. * * @author Sven Fuchs (svenfuchs@artweb-design.de) * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2011 Sven Fuchs, Christian Johansen */ if (typeof sinon == "undefined") { this.sinon = {}; } (function () { var push = [].push; function makeApi(sinon) { sinon.Event = function Event(type, bubbles, cancelable, target) { this.initEvent(type, bubbles, cancelable, target); }; sinon.Event.prototype = { initEvent: function (type, bubbles, cancelable, target) { this.type = type; this.bubbles = bubbles; this.cancelable = cancelable; this.target = target; }, stopPropagation: function () {}, preventDefault: function () { this.defaultPrevented = true; } }; sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) { this.initEvent(type, false, false, target); this.loaded = progressEventRaw.loaded || null; this.total = progressEventRaw.total || null; this.lengthComputable = !!progressEventRaw.total; }; sinon.ProgressEvent.prototype = new sinon.Event(); sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; sinon.CustomEvent = function CustomEvent(type, customData, target) { this.initEvent(type, false, false, target); this.detail = customData.detail || null; }; sinon.CustomEvent.prototype = new sinon.Event(); sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; sinon.EventTarget = { addEventListener: function addEventListener(event, listener) { this.eventListeners = this.eventListeners || {}; this.eventListeners[event] = this.eventListeners[event] || []; push.call(this.eventListeners[event], listener); }, removeEventListener: function removeEventListener(event, listener) { var listeners = this.eventListeners && this.eventListeners[event] || []; for (var i = 0, l = listeners.length; i < l; ++i) { if (listeners[i] == listener) { return listeners.splice(i, 1); } } }, dispatchEvent: function dispatchEvent(event) { var type = event.type; var listeners = this.eventListeners && this.eventListeners[type] || []; for (var i = 0; i < listeners.length; i++) { if (typeof listeners[i] == "function") { listeners[i].call(this, event); } else { listeners[i].handleEvent(event); } } return !!event.defaultPrevented; } }; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require) { var sinon = require("./core"); makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require); } else { makeApi(sinon); } }()); /** * @depend util/core.js */ /** * Logs errors * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ (function (sinon) { // cache a reference to setTimeout, so that our reference won't be stubbed out // when using fake timers and errors will still get logged // https://github.com/cjohansen/Sinon.JS/issues/381 var realSetTimeout = setTimeout; function makeApi(sinon) { function log() {} function logError(label, err) { var msg = label + " threw exception: "; sinon.log(msg + "[" + err.name + "] " + err.message); if (err.stack) { sinon.log(err.stack); } logError.setTimeout(function () { err.message = msg + err.message; throw err; }, 0); }; // wrap realSetTimeout with something we can stub in tests logError.setTimeout = function (func, timeout) { realSetTimeout(func, timeout); } var exports = {}; exports.log = sinon.log = log; exports.logError = sinon.logError = logError; return exports; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend core.js * @depend ../extend.js * @depend event.js * @depend ../log_error.js */ /** * Fake XDomainRequest object */ if (typeof sinon == "undefined") { this.sinon = {}; } // wrapper for global (function (global) { var xdr = { XDomainRequest: global.XDomainRequest }; xdr.GlobalXDomainRequest = global.XDomainRequest; xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined"; xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; function makeApi(sinon) { sinon.xdr = xdr; function FakeXDomainRequest() { this.readyState = FakeXDomainRequest.UNSENT; this.requestBody = null; this.requestHeaders = {}; this.status = 0; this.timeout = null; if (typeof FakeXDomainRequest.onCreate == "function") { FakeXDomainRequest.onCreate(this); } } function verifyState(xdr) { if (xdr.readyState !== FakeXDomainRequest.OPENED) { throw new Error("INVALID_STATE_ERR"); } if (xdr.sendFlag) { throw new Error("INVALID_STATE_ERR"); } } function verifyRequestSent(xdr) { if (xdr.readyState == FakeXDomainRequest.UNSENT) { throw new Error("Request not sent"); } if (xdr.readyState == FakeXDomainRequest.DONE) { throw new Error("Request done"); } } function verifyResponseBodyType(body) { if (typeof body != "string") { var error = new Error("Attempted to respond to fake XDomainRequest with " + body + ", which is not a string."); error.name = "InvalidBodyException"; throw error; } } sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, { open: function open(method, url) { this.method = method; this.url = url; this.responseText = null; this.sendFlag = false; this.readyStateChange(FakeXDomainRequest.OPENED); }, readyStateChange: function readyStateChange(state) { this.readyState = state; var eventName = ""; switch (this.readyState) { case FakeXDomainRequest.UNSENT: break; case FakeXDomainRequest.OPENED: break; case FakeXDomainRequest.LOADING: if (this.sendFlag) { //raise the progress event eventName = "onprogress"; } break; case FakeXDomainRequest.DONE: if (this.isTimeout) { eventName = "ontimeout" } else if (this.errorFlag || (this.status < 200 || this.status > 299)) { eventName = "onerror"; } else { eventName = "onload" } break; } // raising event (if defined) if (eventName) { if (typeof this[eventName] == "function") { try { this[eventName](); } catch (e) { sinon.logError("Fake XHR " + eventName + " handler", e); } } } }, send: function send(data) { verifyState(this); if (!/^(get|head)$/i.test(this.method)) { this.requestBody = data; } this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; this.errorFlag = false; this.sendFlag = true; this.readyStateChange(FakeXDomainRequest.OPENED); if (typeof this.onSend == "function") { this.onSend(this); } }, abort: function abort() { this.aborted = true; this.responseText = null; this.errorFlag = true; if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) { this.readyStateChange(sinon.FakeXDomainRequest.DONE); this.sendFlag = false; } }, setResponseBody: function setResponseBody(body) { verifyRequestSent(this); verifyResponseBodyType(body); var chunkSize = this.chunkSize || 10; var index = 0; this.responseText = ""; do { this.readyStateChange(FakeXDomainRequest.LOADING); this.responseText += body.substring(index, index + chunkSize); index += chunkSize; } while (index < body.length); this.readyStateChange(FakeXDomainRequest.DONE); }, respond: function respond(status, contentType, body) { // content-type ignored, since XDomainRequest does not carry this // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease // test integration across browsers this.status = typeof status == "number" ? status : 200; this.setResponseBody(body || ""); }, simulatetimeout: function simulatetimeout() { this.status = 0; this.isTimeout = true; // Access to this should actually throw an error this.responseText = undefined; this.readyStateChange(FakeXDomainRequest.DONE); } }); sinon.extend(FakeXDomainRequest, { UNSENT: 0, OPENED: 1, LOADING: 3, DONE: 4 }); sinon.useFakeXDomainRequest = function useFakeXDomainRequest() { sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) { if (xdr.supportsXDR) { global.XDomainRequest = xdr.GlobalXDomainRequest; } delete sinon.FakeXDomainRequest.restore; if (keepOnCreate !== true) { delete sinon.FakeXDomainRequest.onCreate; } }; if (xdr.supportsXDR) { global.XDomainRequest = sinon.FakeXDomainRequest; } return sinon.FakeXDomainRequest; }; sinon.FakeXDomainRequest = FakeXDomainRequest; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./core"); require("../extend"); require("./event"); require("../log_error"); makeApi(sinon); module.exports = sinon; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else { makeApi(sinon); } })(typeof global !== "undefined" ? global : self); /** * @depend core.js * @depend ../extend.js * @depend event.js * @depend ../log_error.js */ /** * Fake XMLHttpRequest object * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (global) { var supportsProgress = typeof ProgressEvent !== "undefined"; var supportsCustomEvent = typeof CustomEvent !== "undefined"; var supportsFormData = typeof FormData !== "undefined"; var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest }; sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest; sinonXhr.GlobalActiveXObject = global.ActiveXObject; sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject != "undefined"; sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest != "undefined"; sinonXhr.workingXHR = sinonXhr.supportsXHR ? sinonXhr.GlobalXMLHttpRequest : sinonXhr.supportsActiveX ? function () { return new sinonXhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false; sinonXhr.supportsCORS = sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest()); /*jsl:ignore*/ var unsafeHeaders = { "Accept-Charset": true, "Accept-Encoding": true, Connection: true, "Content-Length": true, Cookie: true, Cookie2: true, "Content-Transfer-Encoding": true, Date: true, Expect: true, Host: true, "Keep-Alive": true, Referer: true, TE: true, Trailer: true, "Transfer-Encoding": true, Upgrade: true, "User-Agent": true, Via: true }; /*jsl:end*/ // Note that for FakeXMLHttpRequest to work pre ES5 // we lose some of the alignment with the spec. // To ensure as close a match as possible, // set responseType before calling open, send or respond; function FakeXMLHttpRequest() { this.readyState = FakeXMLHttpRequest.UNSENT; this.requestHeaders = {}; this.requestBody = null; this.status = 0; this.statusText = ""; this.upload = new UploadProgress(); this.responseType = ""; this.response = ""; if (sinonXhr.supportsCORS) { this.withCredentials = false; } var xhr = this; var events = ["loadstart", "load", "abort", "loadend"]; function addEventListener(eventName) { xhr.addEventListener(eventName, function (event) { var listener = xhr["on" + eventName]; if (listener && typeof listener == "function") { listener.call(this, event); } }); } for (var i = events.length - 1; i >= 0; i--) { addEventListener(events[i]); } if (typeof FakeXMLHttpRequest.onCreate == "function") { FakeXMLHttpRequest.onCreate(this); } } // An upload object is created for each // FakeXMLHttpRequest and allows upload // events to be simulated using uploadProgress // and uploadError. function UploadProgress() { this.eventListeners = { progress: [], load: [], abort: [], error: [] } } UploadProgress.prototype.addEventListener = function addEventListener(event, listener) { this.eventListeners[event].push(listener); }; UploadProgress.prototype.removeEventListener = function removeEventListener(event, listener) { var listeners = this.eventListeners[event] || []; for (var i = 0, l = listeners.length; i < l; ++i) { if (listeners[i] == listener) { return listeners.splice(i, 1); } } }; UploadProgress.prototype.dispatchEvent = function dispatchEvent(event) { var listeners = this.eventListeners[event.type] || []; for (var i = 0, listener; (listener = listeners[i]) != null; i++) { listener(event); } }; function verifyState(xhr) { if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { throw new Error("INVALID_STATE_ERR"); } if (xhr.sendFlag) { throw new Error("INVALID_STATE_ERR"); } } function getHeader(headers, header) { header = header.toLowerCase(); for (var h in headers) { if (h.toLowerCase() == header) { return h; } } return null; } // filtering to enable a white-list version of Sinon FakeXhr, // where whitelisted requests are passed through to real XHR function each(collection, callback) { if (!collection) { return; } for (var i = 0, l = collection.length; i < l; i += 1) { callback(collection[i]); } } function some(collection, callback) { for (var index = 0; index < collection.length; index++) { if (callback(collection[index]) === true) { return true; } } return false; } // largest arity in XHR is 5 - XHR#open var apply = function (obj, method, args) { switch (args.length) { case 0: return obj[method](); case 1: return obj[method](args[0]); case 2: return obj[method](args[0], args[1]); case 3: return obj[method](args[0], args[1], args[2]); case 4: return obj[method](args[0], args[1], args[2], args[3]); case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]); } }; FakeXMLHttpRequest.filters = []; FakeXMLHttpRequest.addFilter = function addFilter(fn) { this.filters.push(fn) }; var IE6Re = /MSIE 6/; FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) { var xhr = new sinonXhr.workingXHR(); each([ "open", "setRequestHeader", "send", "abort", "getResponseHeader", "getAllResponseHeaders", "addEventListener", "overrideMimeType", "removeEventListener" ], function (method) { fakeXhr[method] = function () { return apply(xhr, method, arguments); }; }); var copyAttrs = function (args) { each(args, function (attr) { try { fakeXhr[attr] = xhr[attr] } catch (e) { if (!IE6Re.test(navigator.userAgent)) { throw e; } } }); }; var stateChange = function stateChange() { fakeXhr.readyState = xhr.readyState; if (xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { copyAttrs(["status", "statusText"]); } if (xhr.readyState >= FakeXMLHttpRequest.LOADING) { copyAttrs(["responseText", "response"]); } if (xhr.readyState === FakeXMLHttpRequest.DONE) { copyAttrs(["responseXML"]); } if (fakeXhr.onreadystatechange) { fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr }); } }; if (xhr.addEventListener) { for (var event in fakeXhr.eventListeners) { if (fakeXhr.eventListeners.hasOwnProperty(event)) { each(fakeXhr.eventListeners[event], function (handler) { xhr.addEventListener(event, handler); }); } } xhr.addEventListener("readystatechange", stateChange); } else { xhr.onreadystatechange = stateChange; } apply(xhr, "open", xhrArgs); }; FakeXMLHttpRequest.useFilters = false; function verifyRequestOpened(xhr) { if (xhr.readyState != FakeXMLHttpRequest.OPENED) { throw new Error("INVALID_STATE_ERR - " + xhr.readyState); } } function verifyRequestSent(xhr) { if (xhr.readyState == FakeXMLHttpRequest.DONE) { throw new Error("Request done"); } } function verifyHeadersReceived(xhr) { if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { throw new Error("No headers received"); } } function verifyResponseBodyType(body) { if (typeof body != "string") { var error = new Error("Attempted to respond to fake XMLHttpRequest with " + body + ", which is not a string."); error.name = "InvalidBodyException"; throw error; } } FakeXMLHttpRequest.parseXML = function parseXML(text) { var xmlDoc; if (typeof DOMParser != "undefined") { var parser = new DOMParser(); xmlDoc = parser.parseFromString(text, "text/xml"); } else { xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = "false"; xmlDoc.loadXML(text); } return xmlDoc; }; FakeXMLHttpRequest.statusCodes = { 100: "Continue", 101: "Switching Protocols", 200: "OK", 201: "Created", 202: "Accepted", 203: "Non-Authoritative Information", 204: "No Content", 205: "Reset Content", 206: "Partial Content", 207: "Multi-Status", 300: "Multiple Choice", 301: "Moved Permanently", 302: "Found", 303: "See Other", 304: "Not Modified", 305: "Use Proxy", 307: "Temporary Redirect", 400: "Bad Request", 401: "Unauthorized", 402: "Payment Required", 403: "Forbidden", 404: "Not Found", 405: "Method Not Allowed", 406: "Not Acceptable", 407: "Proxy Authentication Required", 408: "Request Timeout", 409: "Conflict", 410: "Gone", 411: "Length Required", 412: "Precondition Failed", 413: "Request Entity Too Large", 414: "Request-URI Too Long", 415: "Unsupported Media Type", 416: "Requested Range Not Satisfiable", 417: "Expectation Failed", 422: "Unprocessable Entity", 500: "Internal Server Error", 501: "Not Implemented", 502: "Bad Gateway", 503: "Service Unavailable", 504: "Gateway Timeout", 505: "HTTP Version Not Supported" }; function makeApi(sinon) { sinon.xhr = sinonXhr; sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { async: true, open: function open(method, url, async, username, password) { this.method = method; this.url = url; this.async = typeof async == "boolean" ? async : true; this.username = username; this.password = password; this.responseText = null; this.response = this.responseType === "json" ? null : ""; this.responseXML = null; this.requestHeaders = {}; this.sendFlag = false; if (FakeXMLHttpRequest.useFilters === true) { var xhrArgs = arguments; var defake = some(FakeXMLHttpRequest.filters, function (filter) { return filter.apply(this, xhrArgs) }); if (defake) { return FakeXMLHttpRequest.defake(this, arguments); } } this.readyStateChange(FakeXMLHttpRequest.OPENED); }, readyStateChange: function readyStateChange(state) { this.readyState = state; if (typeof this.onreadystatechange == "function") { try { this.onreadystatechange(); } catch (e) { sinon.logError("Fake XHR onreadystatechange handler", e); } } switch (this.readyState) { case FakeXMLHttpRequest.DONE: if (supportsProgress) { this.upload.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100})); this.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100})); } this.upload.dispatchEvent(new sinon.Event("load", false, false, this)); this.dispatchEvent(new sinon.Event("load", false, false, this)); this.dispatchEvent(new sinon.Event("loadend", false, false, this)); break; } this.dispatchEvent(new sinon.Event("readystatechange")); }, setRequestHeader: function setRequestHeader(header, value) { verifyState(this); if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { throw new Error("Refused to set unsafe header \"" + header + "\""); } if (this.requestHeaders[header]) { this.requestHeaders[header] += "," + value; } else { this.requestHeaders[header] = value; } }, // Helps testing setResponseHeaders: function setResponseHeaders(headers) { verifyRequestOpened(this); this.responseHeaders = {}; for (var header in headers) { if (headers.hasOwnProperty(header)) { this.responseHeaders[header] = headers[header]; } } if (this.async) { this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); } else { this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED; } }, // Currently treats ALL data as a DOMString (i.e. no Document) send: function send(data) { verifyState(this); if (!/^(get|head)$/i.test(this.method)) { var contentType = getHeader(this.requestHeaders, "Content-Type"); if (this.requestHeaders[contentType]) { var value = this.requestHeaders[contentType].split(";"); this.requestHeaders[contentType] = value[0] + ";charset=utf-8"; } else if (supportsFormData && !(data instanceof FormData)) { this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; } this.requestBody = data; } this.errorFlag = false; this.sendFlag = this.async; this.response = this.responseType === "json" ? null : ""; this.readyStateChange(FakeXMLHttpRequest.OPENED); if (typeof this.onSend == "function") { this.onSend(this); } this.dispatchEvent(new sinon.Event("loadstart", false, false, this)); }, abort: function abort() { this.aborted = true; this.responseText = null; this.response = this.responseType === "json" ? null : ""; this.errorFlag = true; this.requestHeaders = {}; this.responseHeaders = {}; if (this.readyState > FakeXMLHttpRequest.UNSENT && this.sendFlag) { this.readyStateChange(FakeXMLHttpRequest.DONE); this.sendFlag = false; } this.readyState = FakeXMLHttpRequest.UNSENT; this.dispatchEvent(new sinon.Event("abort", false, false, this)); this.upload.dispatchEvent(new sinon.Event("abort", false, false, this)); if (typeof this.onerror === "function") { this.onerror(); } }, getResponseHeader: function getResponseHeader(header) { if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { return null; } if (/^Set-Cookie2?$/i.test(header)) { return null; } header = getHeader(this.responseHeaders, header); return this.responseHeaders[header] || null; }, getAllResponseHeaders: function getAllResponseHeaders() { if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { return ""; } var headers = ""; for (var header in this.responseHeaders) { if (this.responseHeaders.hasOwnProperty(header) && !/^Set-Cookie2?$/i.test(header)) { headers += header + ": " + this.responseHeaders[header] + "\r\n"; } } return headers; }, setResponseBody: function setResponseBody(body) { verifyRequestSent(this); verifyHeadersReceived(this); verifyResponseBodyType(body); var chunkSize = this.chunkSize || 10; var index = 0; this.responseText = ""; do { if (this.async) { this.readyStateChange(FakeXMLHttpRequest.LOADING); } this.responseText += body.substring(index, index + chunkSize); index += chunkSize; } while (index < body.length); var type = this.getResponseHeader("Content-Type"); if (this.responseText && (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) { try { this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); } catch (e) { // Unable to parse XML - no biggie } } this.response = this.responseType === "json" ? JSON.parse(this.responseText) : this.responseText; this.readyStateChange(FakeXMLHttpRequest.DONE); }, respond: function respond(status, headers, body) { this.status = typeof status == "number" ? status : 200; this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; this.setResponseHeaders(headers || {}); this.setResponseBody(body || ""); }, uploadProgress: function uploadProgress(progressEventRaw) { if (supportsProgress) { this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); } }, downloadProgress: function downloadProgress(progressEventRaw) { if (supportsProgress) { this.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); } }, uploadError: function uploadError(error) { if (supportsCustomEvent) { this.upload.dispatchEvent(new sinon.CustomEvent("error", {detail: error})); } } }); sinon.extend(FakeXMLHttpRequest, { UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4 }); sinon.useFakeXMLHttpRequest = function () { FakeXMLHttpRequest.restore = function restore(keepOnCreate) { if (sinonXhr.supportsXHR) { global.XMLHttpRequest = sinonXhr.GlobalXMLHttpRequest; } if (sinonXhr.supportsActiveX) { global.ActiveXObject = sinonXhr.GlobalActiveXObject; } delete FakeXMLHttpRequest.restore; if (keepOnCreate !== true) { delete FakeXMLHttpRequest.onCreate; } }; if (sinonXhr.supportsXHR) { global.XMLHttpRequest = FakeXMLHttpRequest; } if (sinonXhr.supportsActiveX) { global.ActiveXObject = function ActiveXObject(objId) { if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { return new FakeXMLHttpRequest(); } return new sinonXhr.GlobalActiveXObject(objId); }; } return FakeXMLHttpRequest; }; sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./core"); require("../extend"); require("./event"); require("../log_error"); makeApi(sinon); module.exports = sinon; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (typeof sinon === "undefined") { return; } else { makeApi(sinon); } })(typeof global !== "undefined" ? global : self); /** * @depend fake_xdomain_request.js * @depend fake_xml_http_request.js * @depend ../format.js * @depend ../log_error.js */ /** * The Sinon "server" mimics a web server that receives requests from * sinon.FakeXMLHttpRequest and provides an API to respond to those requests, * both synchronously and asynchronously. To respond synchronuously, canned * answers have to be provided upfront. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ if (typeof sinon == "undefined") { var sinon = {}; } (function () { var push = [].push; function F() {} function create(proto) { F.prototype = proto; return new F(); } function responseArray(handler) { var response = handler; if (Object.prototype.toString.call(handler) != "[object Array]") { response = [200, {}, handler]; } if (typeof response[2] != "string") { throw new TypeError("Fake server response body should be string, but was " + typeof response[2]); } return response; } var wloc = typeof window !== "undefined" ? window.location : {}; var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); function matchOne(response, reqMethod, reqUrl) { var rmeth = response.method; var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); var url = response.url; var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); return matchMethod && matchUrl; } function match(response, request) { var requestUrl = request.url; if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { requestUrl = requestUrl.replace(rCurrLoc, ""); } if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { if (typeof response.response == "function") { var ru = response.url; var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []); return response.response.apply(response, args); } return true; } return false; } function makeApi(sinon) { sinon.fakeServer = { create: function () { var server = create(this); if (!sinon.xhr.supportsCORS) { this.xhr = sinon.useFakeXDomainRequest(); } else { this.xhr = sinon.useFakeXMLHttpRequest(); } server.requests = []; this.xhr.onCreate = function (xhrObj) { server.addRequest(xhrObj); }; return server; }, addRequest: function addRequest(xhrObj) { var server = this; push.call(this.requests, xhrObj); xhrObj.onSend = function () { server.handleRequest(this); if (server.respondImmediately) { server.respond(); } else if (server.autoRespond && !server.responding) { setTimeout(function () { server.responding = false; server.respond(); }, server.autoRespondAfter || 10); server.responding = true; } }; }, getHTTPMethod: function getHTTPMethod(request) { if (this.fakeHTTPMethods && /post/i.test(request.method)) { var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); return !!matches ? matches[1] : request.method; } return request.method; }, handleRequest: function handleRequest(xhr) { if (xhr.async) { if (!this.queue) { this.queue = []; } push.call(this.queue, xhr); } else { this.processRequest(xhr); } }, log: function log(response, request) { var str; str = "Request:\n" + sinon.format(request) + "\n\n"; str += "Response:\n" + sinon.format(response) + "\n\n"; sinon.log(str); }, respondWith: function respondWith(method, url, body) { if (arguments.length == 1 && typeof method != "function") { this.response = responseArray(method); return; } if (!this.responses) { this.responses = []; } if (arguments.length == 1) { body = method; url = method = null; } if (arguments.length == 2) { body = url; url = method; method = null; } push.call(this.responses, { method: method, url: url, response: typeof body == "function" ? body : responseArray(body) }); }, respond: function respond() { if (arguments.length > 0) { this.respondWith.apply(this, arguments); } var queue = this.queue || []; var requests = queue.splice(0, queue.length); var request; while (request = requests.shift()) { this.processRequest(request); } }, processRequest: function processRequest(request) { try { if (request.aborted) { return; } var response = this.response || [404, {}, ""]; if (this.responses) { for (var l = this.responses.length, i = l - 1; i >= 0; i--) { if (match.call(this, this.responses[i], request)) { response = this.responses[i].response; break; } } } if (request.readyState != 4) { this.log(response, request); request.respond(response[0], response[1], response[2]); } } catch (e) { sinon.logError("Fake server request processing", e); } }, restore: function restore() { return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); } }; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./core"); require("./fake_xdomain_request"); require("./fake_xml_http_request"); require("../format"); makeApi(sinon); module.exports = sinon; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else { makeApi(sinon); } }()); /** * @depend fake_server.js * @depend fake_timers.js */ /** * Add-on for sinon.fakeServer that automatically handles a fake timer along with * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, * it polls the object for completion with setInterval. Dispite the direct * motivation, there is nothing jQuery-specific in this file, so it can be used * in any environment where the ajax implementation depends on setInterval or * setTimeout. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function () { function makeApi(sinon) { function Server() {} Server.prototype = sinon.fakeServer; sinon.fakeServerWithClock = new Server(); sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { if (xhr.async) { if (typeof setTimeout.clock == "object") { this.clock = setTimeout.clock; } else { this.clock = sinon.useFakeTimers(); this.resetClock = true; } if (!this.longestTimeout) { var clockSetTimeout = this.clock.setTimeout; var clockSetInterval = this.clock.setInterval; var server = this; this.clock.setTimeout = function (fn, timeout) { server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); return clockSetTimeout.apply(this, arguments); }; this.clock.setInterval = function (fn, timeout) { server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); return clockSetInterval.apply(this, arguments); }; } } return sinon.fakeServer.addRequest.call(this, xhr); }; sinon.fakeServerWithClock.respond = function respond() { var returnVal = sinon.fakeServer.respond.apply(this, arguments); if (this.clock) { this.clock.tick(this.longestTimeout || 0); this.longestTimeout = 0; if (this.resetClock) { this.clock.restore(); this.resetClock = false; } } return returnVal; }; sinon.fakeServerWithClock.restore = function restore() { if (this.clock) { this.clock.restore(); } return sinon.fakeServer.restore.apply(this, arguments); }; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require) { var sinon = require("./core"); require("./fake_server"); require("./fake_timers"); makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require); } else { makeApi(sinon); } }()); /** * @depend util/core.js * @depend extend.js * @depend collection.js * @depend util/fake_timers.js * @depend util/fake_server_with_clock.js */ /** * Manages fake collections as well as fake utilities such as Sinon's * timers and fake XHR implementation in one convenient object. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function () { function makeApi(sinon) { var push = [].push; function exposeValue(sandbox, config, key, value) { if (!value) { return; } if (config.injectInto && !(key in config.injectInto)) { config.injectInto[key] = value; sandbox.injectedKeys.push(key); } else { push.call(sandbox.args, value); } } function prepareSandboxFromConfig(config) { var sandbox = sinon.create(sinon.sandbox); if (config.useFakeServer) { if (typeof config.useFakeServer == "object") { sandbox.serverPrototype = config.useFakeServer; } sandbox.useFakeServer(); } if (config.useFakeTimers) { if (typeof config.useFakeTimers == "object") { sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); } else { sandbox.useFakeTimers(); } } return sandbox; } sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { useFakeTimers: function useFakeTimers() { this.clock = sinon.useFakeTimers.apply(sinon, arguments); return this.add(this.clock); }, serverPrototype: sinon.fakeServer, useFakeServer: function useFakeServer() { var proto = this.serverPrototype || sinon.fakeServer; if (!proto || !proto.create) { return null; } this.server = proto.create(); return this.add(this.server); }, inject: function (obj) { sinon.collection.inject.call(this, obj); if (this.clock) { obj.clock = this.clock; } if (this.server) { obj.server = this.server; obj.requests = this.server.requests; } obj.match = sinon.match; return obj; }, restore: function () { sinon.collection.restore.apply(this, arguments); this.restoreContext(); }, restoreContext: function () { if (this.injectedKeys) { for (var i = 0, j = this.injectedKeys.length; i < j; i++) { delete this.injectInto[this.injectedKeys[i]]; } this.injectedKeys = []; } }, create: function (config) { if (!config) { return sinon.create(sinon.sandbox); } var sandbox = prepareSandboxFromConfig(config); sandbox.args = sandbox.args || []; sandbox.injectedKeys = []; sandbox.injectInto = config.injectInto; var prop, value, exposed = sandbox.inject({}); if (config.properties) { for (var i = 0, l = config.properties.length; i < l; i++) { prop = config.properties[i]; value = exposed[prop] || prop == "sandbox" && sandbox; exposeValue(sandbox, config, prop, value); } } else { exposeValue(sandbox, config, "sandbox", value); } return sandbox; }, match: sinon.match }); sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; return sinon.sandbox; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./extend"); require("./util/fake_server_with_clock"); require("./util/fake_timers"); require("./collection"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }()); /** * @depend util/core.js * @depend sandbox.js */ /** * Test function, sandboxes fakes * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinon) { function makeApi(sinon) { var slice = Array.prototype.slice; function test(callback) { var type = typeof callback; if (type != "function") { throw new TypeError("sinon.test needs to wrap a test function, got " + type); } function sinonSandboxedTest() { var config = sinon.getConfig(sinon.config); config.injectInto = config.injectIntoThis && this || config.injectInto; var sandbox = sinon.sandbox.create(config); var args = slice.call(arguments); var oldDone = args.length && args[args.length - 1]; var exception, result; if (typeof oldDone == "function") { args[args.length - 1] = function sinonDone(result) { if (result) { sandbox.restore(); throw exception; } else { sandbox.verifyAndRestore(); } oldDone(result); }; } try { result = callback.apply(this, args.concat(sandbox.args)); } catch (e) { exception = e; } if (typeof oldDone != "function") { if (typeof exception !== "undefined") { sandbox.restore(); throw exception; } else { sandbox.verifyAndRestore(); } } return result; } if (callback.length) { return function sinonAsyncSandboxedTest(callback) { return sinonSandboxedTest.apply(this, arguments); }; } return sinonSandboxedTest; } test.config = { injectIntoThis: true, injectInto: null, properties: ["spy", "stub", "mock", "clock", "server", "requests"], useFakeTimers: true, useFakeServer: true }; sinon.test = test; return test; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./sandbox"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (sinon) { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend util/core.js * @depend test.js */ /** * Test case, sandboxes all test functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinon) { function createTest(property, setUp, tearDown) { return function () { if (setUp) { setUp.apply(this, arguments); } var exception, result; try { result = property.apply(this, arguments); } catch (e) { exception = e; } if (tearDown) { tearDown.apply(this, arguments); } if (exception) { throw exception; } return result; }; } function makeApi(sinon) { function testCase(tests, prefix) { if (!tests || typeof tests != "object") { throw new TypeError("sinon.testCase needs an object with test functions"); } prefix = prefix || "test"; var rPrefix = new RegExp("^" + prefix); var methods = {}, testName, property, method; var setUp = tests.setUp; var tearDown = tests.tearDown; for (testName in tests) { if (tests.hasOwnProperty(testName) && !/^(setUp|tearDown)$/.test(testName)) { property = tests[testName]; if (typeof property == "function" && rPrefix.test(testName)) { method = property; if (setUp || tearDown) { method = createTest(property, setUp, tearDown); } methods[testName] = sinon.test(method); } else { methods[testName] = tests[testName]; } } } return methods; } sinon.testCase = testCase; return testCase; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./test"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null)); /** * @depend times_in_words.js * @depend util/core.js * @depend match.js * @depend format.js */ /** * Assertions matching the test spy retrieval interface. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinon, global) { var slice = Array.prototype.slice; function makeApi(sinon) { var assert; function verifyIsStub() { var method; for (var i = 0, l = arguments.length; i < l; ++i) { method = arguments[i]; if (!method) { assert.fail("fake is not a spy"); } if (method.proxy && method.proxy.isSinonProxy) { verifyIsStub(method.proxy); } else { if (typeof method != "function") { assert.fail(method + " is not a function"); } if (typeof method.getCall != "function") { assert.fail(method + " is not stubbed"); } } } } function failAssertion(object, msg) { object = object || global; var failMethod = object.fail || assert.fail; failMethod.call(object, msg); } function mirrorPropAsAssertion(name, method, message) { if (arguments.length == 2) { message = method; method = name; } assert[name] = function (fake) { verifyIsStub(fake); var args = slice.call(arguments, 1); var failed = false; if (typeof method == "function") { failed = !method(fake); } else { failed = typeof fake[method] == "function" ? !fake[method].apply(fake, args) : !fake[method]; } if (failed) { failAssertion(this, (fake.printf || fake.proxy.printf).apply(fake, [message].concat(args))); } else { assert.pass(name); } }; } function exposedName(prefix, prop) { return !prefix || /^fail/.test(prop) ? prop : prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1); } assert = { failException: "AssertError", fail: function fail(message) { var error = new Error(message); error.name = this.failException || assert.failException; throw error; }, pass: function pass(assertion) {}, callOrder: function assertCallOrder() { verifyIsStub.apply(null, arguments); var expected = "", actual = ""; if (!sinon.calledInOrder(arguments)) { try { expected = [].join.call(arguments, ", "); var calls = slice.call(arguments); var i = calls.length; while (i) { if (!calls[--i].called) { calls.splice(i, 1); } } actual = sinon.orderByFirstCall(calls).join(", "); } catch (e) { // If this fails, we'll just fall back to the blank string } failAssertion(this, "expected " + expected + " to be " + "called in order but were called as " + actual); } else { assert.pass("callOrder"); } }, callCount: function assertCallCount(method, count) { verifyIsStub(method); if (method.callCount != count) { var msg = "expected %n to be called " + sinon.timesInWords(count) + " but was called %c%C"; failAssertion(this, method.printf(msg)); } else { assert.pass("callCount"); } }, expose: function expose(target, options) { if (!target) { throw new TypeError("target is null or undefined"); } var o = options || {}; var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; for (var method in this) { if (method != "expose" && (includeFail || !/^(fail)/.test(method))) { target[exposedName(prefix, method)] = this[method]; } } return target; }, match: function match(actual, expectation) { var matcher = sinon.match(expectation); if (matcher.test(actual)) { assert.pass("match"); } else { var formatted = [ "expected value to match", " expected = " + sinon.format(expectation), " actual = " + sinon.format(actual) ] failAssertion(this, formatted.join("\n")); } } }; mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; }, "expected %n to not have been called but was called %c%C"); mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new"); mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new"); mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C"); mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C"); mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); mirrorPropAsAssertion("threw", "%n did not throw exception%C"); mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); sinon.assert = assert; return assert; } var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./match"); require("./format"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (!sinon) { return; } else { makeApi(sinon); } }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global)); return sinon; }));