From 01ecc3ce5b6ab71ba7267c571cac309a333dd801 Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Sat, 12 Mar 2016 00:59:30 +0000 Subject: [PATCH] Upgrade Sinon.JS to 1.17.3 No major changes for us other than a bugfix that makes the following work as expected: var clock = this.sandbox.useFakeTimers(); setTimeout(function () { clock.tick(10); }); click.tick(1); // Expected: 11ms is recorded // Actual: 1ms is record This was broken up until Sinon 1.16.0 (Lolex 1.3.0) because it saved the "clock.now" value before running any pending timeout callbacks. Then it unconditionally assigned the "clock.now" value to 'oldNow + ticked', which discarded ticks made by a callback. Change-Id: I2775f4c6353aef12ced6dc45e73fe8d4e49c2b68 --- .../{sinon-1.15.4.js => sinon-1.17.3.js} | 2320 ++++++++++------- resources/lib/sinonjs/sinon-ie-1.15.4.js | 103 - tests/qunit/QUnitTestResources.php | 9 +- 3 files changed, 1405 insertions(+), 1027 deletions(-) rename resources/lib/sinonjs/{sinon-1.15.4.js => sinon-1.17.3.js} (78%) delete mode 100644 resources/lib/sinonjs/sinon-ie-1.15.4.js diff --git a/resources/lib/sinonjs/sinon-1.15.4.js b/resources/lib/sinonjs/sinon-1.17.3.js similarity index 78% rename from resources/lib/sinonjs/sinon-1.15.4.js rename to resources/lib/sinonjs/sinon-1.17.3.js index 20bc9e208d..d77b317587 100644 --- a/resources/lib/sinonjs/sinon-1.15.4.js +++ b/resources/lib/sinonjs/sinon-1.17.3.js @@ -1,5 +1,5 @@ /** - * Sinon.JS 1.15.4, 2015/06/27 + * Sinon.JS 1.17.3, 2016/01/27 * * @author Christian Johansen (christian@cjohansen.no) * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS @@ -671,8 +671,7 @@ }); !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'"); - } + var NOOP = function () { return undefined; }; + var timeoutResult = setTimeout(NOOP, 0); + var addTimerReturnsObject = typeof timeoutResult === "object"; + clearTimeout(timeoutResult); - while (i--) { - parsed = parseInt(strings[i], 10); + var NativeDate = Date; + var uniqueTimerId = 1; - if (parsed >= 60) { - throw new Error("Invalid time " + str); + /** + * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into + * number of milliseconds. This is used to support human-readable strings passed + * to clock.tick() + */ + function parseTime(str) { + if (!str) { + return 0; } - ms += parsed * Math.pow(60, (l - i - 1)); - } + var strings = str.split(":"); + var l = strings.length, i = l; + var ms = 0, parsed; - return ms * 1000; -} + if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { + throw new Error("tick only understands numbers, 'm:s' and 'h:m:s'. Each part must be two digits"); + } -/** - * 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"); -} + while (i--) { + parsed = parseInt(strings[i], 10); -function inRange(from, to, timer) { - return timer && timer.callAt >= from && timer.callAt <= to; -} + if (parsed >= 60) { + throw new Error("Invalid time " + str); + } -function mirrorDateProperties(target, source) { - if (source.now) { - target.now = function now() { - return target.clock.now; - }; - } else { - delete target.now; + ms += parsed * Math.pow(60, (l - i - 1)); + } + + return ms * 1000; } - if (source.toSource) { - target.toSource = function toSource() { - return source.toSource(); - }; - } else { - delete target.toSource; + /** + * 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"); } - target.toString = function toString() { - return source.toString(); - }; + function inRange(from, to, timer) { + return timer && timer.callAt >= from && timer.callAt <= to; + } - target.prototype = source.prototype; - target.parse = source.parse; - target.UTC = source.UTC; - target.prototype.toUTCString = source.prototype.toUTCString; + function mirrorDateProperties(target, source) { + var prop; + for (prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } - for (var prop in source) { - if (source.hasOwnProperty(prop)) { - target[prop] = source[prop]; + // set special now implementation + if (source.now) { + target.now = function now() { + return target.clock.now; + }; + } else { + delete target.now; } - } - return target; -} + // set special toSource implementation + if (source.toSource) { + target.toSource = function toSource() { + return source.toSource(); + }; + } else { + delete target.toSource; + } -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); -} + // set special toString implementation + target.toString = function toString() { + return source.toString(); + }; -function addTimer(clock, timer) { - if (typeof timer.func === "undefined") { - throw new Error("Callback must be provided to timer calls"); - } + target.prototype = source.prototype; + target.parse = source.parse; + target.UTC = source.UTC; + target.prototype.toUTCString = source.prototype.toUTCString; + + 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); + } + } - if (!clock.timers) { - clock.timers = {}; + return mirrorDateProperties(ClockDate, NativeDate); } - timer.id = id++; - timer.createdAt = clock.now; - timer.callAt = clock.now + (timer.delay || 0); + function addTimer(clock, timer) { + if (timer.func === undefined) { + throw new Error("Callback must be provided to timer calls"); + } + + if (!clock.timers) { + clock.timers = {}; + } - clock.timers[timer.id] = timer; + timer.id = uniqueTimerId++; + timer.createdAt = clock.now; + timer.callAt = clock.now + (timer.delay || (clock.duringTick ? 1 : 0)); + + clock.timers[timer.id] = timer; + + if (addTimerReturnsObject) { + return { + id: timer.id, + ref: NOOP, + unref: NOOP + }; + } - 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; + function compareTimers(a, b) { + // Sort first by absolute timing + if (a.callAt < b.callAt) { + return -1; + } + if (a.callAt > b.callAt) { + return 1; } - if (!timer || ~compareTimers(timer, timers[id])) { - timer = timers[id]; + // Sort next by immediate, immediate timers take precedence + if (a.immediate && !b.immediate) { + return -1; + } + if (!a.immediate && b.immediate) { + return 1; } - } - return timer; -} + // Sort next by creation time, earlier-created timers take precedence + if (a.createdAt < b.createdAt) { + return -1; + } + if (a.createdAt > b.createdAt) { + return 1; + } -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 id, lower-id timers take precedence + if (a.id < b.id) { + return -1; + } + if (a.id > b.id) { + return 1; + } - // Sort next by immediate, immediate timers take precedence - if (a.immediate && !b.immediate) { - return -1; - } - if (!a.immediate && b.immediate) { - return 1; + // As timer ids are unique, no fallback `0` is necessary } - // Sort next by creation time, earlier-created timers take precedence - if (a.createdAt < b.createdAt) { - return -1; - } - if (a.createdAt > b.createdAt) { - return 1; - } + function firstTimerInRange(clock, from, to) { + var timers = clock.timers, + timer = null, + id, + isInRange; - // Sort next by id, lower-id timers take precedence - if (a.id < b.id) { - return -1; - } - if (a.id > b.id) { - return 1; - } + for (id in timers) { + if (timers.hasOwnProperty(id)) { + isInRange = inRange(from, to, timers[id]); - // As timer ids are unique, no fallback `0` is necessary -} + if (isInRange && (!timer || compareTimers(timer, timers[id]) === 1)) { + timer = timers[id]; + } + } + } -function callTimer(clock, timer) { - if (typeof timer.interval == "number") { - clock.timers[timer.id].callAt += timer.interval; - } else { - delete clock.timers[timer.id]; + return timer; } - try { - if (typeof timer.func == "function") { - timer.func.apply(null, timer.args); - } else { - eval(timer.func); - } - } catch (e) { - var exception = e; - } + function firstTimer(clock) { + var timers = clock.timers, + timer = null, + id; - if (!clock.timers[timer.id]) { - if (exception) { - throw exception; + for (id in timers) { + if (timers.hasOwnProperty(id)) { + if (!timer || compareTimers(timer, timers[id]) === 1) { + timer = timers[id]; + } + } } - return; - } - if (exception) { - throw exception; + return timer; } -} - -function uninstall(clock, target) { - var method; - for (var i = 0, l = clock.methods.length; i < l; i++) { - method = clock.methods[i]; + function callTimer(clock, timer) { + var exception; - if (target[method].hadOwnProperty) { - target[method] = clock["_" + method]; + if (typeof timer.interval === "number") { + clock.timers[timer.id].callAt += timer.interval; } else { - try { - delete target[method]; - } catch (e) {} + delete clock.timers[timer.id]; } - } - - // 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]; + try { + if (typeof timer.func === "function") { + timer.func.apply(null, timer.args); + } else { + eval(timer.func); } + } catch (e) { + exception = e; } - } - - 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() - }; + if (!clock.timers[timer.id]) { + if (exception) { + throw exception; + } + return; + } - clock.Date.clock = clock; + if (exception) { + throw exception; + } + } - clock.setTimeout = function setTimeout(func, timeout) { - return addTimer(clock, { - func: func, - args: Array.prototype.slice.call(arguments, 2), - delay: timeout - }); - }; + function timerType(timer) { + if (timer.immediate) { + return "Immediate"; + } else if (typeof timer.interval !== "undefined") { + return "Interval"; + } else { + return "Timeout"; + } + } - clock.clearTimeout = function clearTimeout(timerId) { + function clearTimer(clock, timerId, ttype) { 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 + timerId = timerId.id; } - if (timerId in clock.timers) { - delete clock.timers[timerId]; + + if (clock.timers.hasOwnProperty(timerId)) { + // check that the ID matches a timer of the correct type + var timer = clock.timers[timerId]; + if (timerType(timer) === ttype) { + delete clock.timers[timerId]; + } else { + throw new Error("Cannot clear timer: timer created with set" + ttype + "() but cleared with clear" + timerType(timer) + "()"); + } } - }; + } - clock.setInterval = function setInterval(func, timeout) { - return addTimer(clock, { - func: func, - args: Array.prototype.slice.call(arguments, 2), - delay: timeout, - interval: timeout - }); - }; + function uninstall(clock, target) { + var method, + i, + l; - clock.clearInterval = function clearInterval(timerId) { - clock.clearTimeout(timerId); - }; + for (i = 0, l = clock.methods.length; i < l; i++) { + method = clock.methods[i]; - clock.setImmediate = function setImmediate(func) { - return addTimer(clock, { - func: func, - args: Array.prototype.slice.call(arguments, 1), - immediate: true - }); - }; + if (target[method].hadOwnProperty) { + target[method] = clock["_" + method]; + } else { + try { + delete target[method]; + } catch (ignore) {} + } + } - clock.clearImmediate = function clearImmediate(timerId) { - clock.clearTimeout(timerId); - }; + // Prevent multiple executions which will completely remove these props + clock.methods = []; + } - 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); + function hijackMethod(target, method, clock) { + var prop; - 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; + 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 (prop in clock[method]) { + if (clock[method].hasOwnProperty(prop)) { + target[method][prop] = clock[method][prop]; } } - - timer = firstTimerInRange(clock, previous, tickTo); - previous = tickFrom; } - clock.now = tickTo; + target[method].clock = clock; + } + + var timers = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setImmediate: global.setImmediate, + clearImmediate: global.clearImmediate, + setInterval: setInterval, + clearInterval: clearInterval, + Date: Date + }; + + var keys = Object.keys || function (obj) { + var ks = [], + key; - if (firstException) { - throw firstException; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + ks.push(key); + } } - return clock.now; + return ks; }; - clock.reset = function reset() { - clock.timers = {}; - }; + exports.timers = timers; - return clock; -}; + function createClock(now) { + var clock = { + now: getEpoch(now), + timeouts: {}, + Date: createDate() + }; -exports.install = function install(target, now, toFake) { - if (typeof target === "number") { - toFake = now; - now = target; - target = null; - } + clock.Date.clock = clock; - if (!target) { - target = global; - } + clock.setTimeout = function setTimeout(func, timeout) { + return addTimer(clock, { + func: func, + args: Array.prototype.slice.call(arguments, 2), + delay: timeout + }); + }; - var clock = createClock(now); + clock.clearTimeout = function clearTimeout(timerId) { + return clearTimer(clock, timerId, "Timeout"); + }; - clock.uninstall = function () { - uninstall(clock, target); - }; + clock.setInterval = function setInterval(func, timeout) { + return addTimer(clock, { + func: func, + args: Array.prototype.slice.call(arguments, 2), + delay: timeout, + interval: timeout + }); + }; - clock.methods = toFake || []; + clock.clearInterval = function clearInterval(timerId) { + return clearTimer(clock, timerId, "Interval"); + }; - if (clock.methods.length === 0) { - clock.methods = keys(timers); - } + clock.setImmediate = function setImmediate(func) { + return addTimer(clock, { + func: func, + args: Array.prototype.slice.call(arguments, 1), + immediate: true + }); + }; + + clock.clearImmediate = function clearImmediate(timerId) { + return clearTimer(clock, timerId, "Immediate"); + }; + + 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 oldNow; + + clock.duringTick = true; - for (var i = 0, l = clock.methods.length; i < l; i++) { - hijackMethod(target, clock.methods[i], clock); + var firstException; + while (timer && tickFrom <= tickTo) { + if (clock.timers[timer.id]) { + tickFrom = clock.now = timer.callAt; + try { + oldNow = clock.now; + callTimer(clock, timer); + // compensate for any setSystemTime() call during timer callback + if (oldNow !== clock.now) { + tickFrom += clock.now - oldNow; + tickTo += clock.now - oldNow; + previous += clock.now - oldNow; + } + } catch (e) { + firstException = firstException || e; + } + } + + timer = firstTimerInRange(clock, previous, tickTo); + previous = tickFrom; + } + + clock.duringTick = false; + clock.now = tickTo; + + if (firstException) { + throw firstException; + } + + return clock.now; + }; + + clock.next = function next() { + var timer = firstTimer(clock); + if (!timer) { + return clock.now; + } + + clock.duringTick = true; + try { + clock.now = timer.callAt; + callTimer(clock, timer); + return clock.now; + } finally { + clock.duringTick = false; + } + }; + + clock.reset = function reset() { + clock.timers = {}; + }; + + clock.setSystemTime = function setSystemTime(now) { + // determine time difference + var newNow = getEpoch(now); + var difference = newNow - clock.now; + + // update 'system clock' + clock.now = newNow; + + // update timers and intervals to keep them stable + for (var id in clock.timers) { + if (clock.timers.hasOwnProperty(id)) { + var timer = clock.timers[id]; + timer.createdAt += difference; + timer.callAt += difference; + } + } + }; + + return clock; } + exports.createClock = createClock; + + exports.install = function install(target, now, toFake) { + var i, + l; + + 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 (i = 0, l = clock.methods.length; i < l; i++) { + hijackMethod(target, clock.methods[i], clock); + } + + return clock; + }; - return clock; -}; +}(global || this)); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}]},{},[1])(1) @@ -1106,17 +1235,18 @@ exports.install = function install(target, now, toFake) { * * Copyright (c) 2010-2013 Christian Johansen */ - var sinon = (function () { "use strict"; - - var sinon; + // eslint-disable-line no-unused-vars + + var sinonModule; 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"); + sinonModule = module.exports = require("./sinon/util/core"); require("./sinon/extend"); + require("./sinon/walk"); require("./sinon/typeOf"); require("./sinon/times_in_words"); require("./sinon/spy"); @@ -1138,12 +1268,12 @@ var sinon = (function () { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); - sinon = module.exports; + sinonModule = module.exports; } else { - sinon = {}; + sinonModule = {}; } - return sinon; + return sinonModule; }()); /** @@ -1157,9 +1287,9 @@ var sinon = (function () { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { - var div = typeof document != "undefined" && document.createElement("div"); +(function (sinonGlobal) { + + var div = typeof document !== "undefined" && document.createElement("div"); var hasOwn = Object.prototype.hasOwnProperty; function isDOMNode(obj) { @@ -1167,7 +1297,7 @@ var sinon = (function () { try { obj.appendChild(div); - success = div.parentNode == obj; + success = div.parentNode === obj; } catch (e) { return false; } finally { @@ -1214,18 +1344,20 @@ var sinon = (function () { throw new TypeError("Should wrap property of object"); } - if (typeof method != "function" && typeof method != "object") { + if (typeof method !== "function" && typeof method !== "object") { throw new TypeError("Method wrapper should be a function or a property descriptor"); } function checkWrappedMethod(wrappedMethod) { + var error; + 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"; + var verb = wrappedMethod.returns ? "stubbed" : "spied on"; error = new TypeError("Attempted to wrap " + property + " which is already " + verb); } @@ -1237,16 +1369,15 @@ var sinon = (function () { } } - var error, wrappedMethod; + var error, wrappedMethod, i; // 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; + var methodDesc = (typeof method === "function") ? {value: method} : method; + var wrappedMethodDesc = sinon.getPropertyDescriptor(object, property); if (!wrappedMethodDesc) { error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + @@ -1293,7 +1424,7 @@ var sinon = (function () { // In some cases `delete` may throw an error try { delete object[property]; - } catch (e) {} + } catch (e) {} // eslint-disable-line no-empty // For native code functions `delete` fails without throwing an error // on Chrome < 43, PhantomJS, etc. } else if (hasES5Support) { @@ -1327,12 +1458,8 @@ var sinon = (function () { return a.test(b); } - if (typeof a != "object" || typeof b != "object") { - if (isReallyNaN(a) && isReallyNaN(b)) { - return true; - } else { - return a === b; - } + if (typeof a !== "object" || typeof b !== "object") { + return isReallyNaN(a) && isReallyNaN(b) || a === b; } if (isElement(a) || isElement(b)) { @@ -1353,37 +1480,43 @@ var sinon = (function () { } var aString = Object.prototype.toString.call(a); - if (aString != Object.prototype.toString.call(b)) { + if (aString !== Object.prototype.toString.call(b)) { return false; } - if (aString == "[object Date]") { + if (aString === "[object Date]") { return a.valueOf() === b.valueOf(); } - var prop, aLength = 0, bLength = 0; + var prop; + var aLength = 0; + var bLength = 0; - if (aString == "[object Array]" && a.length !== b.length) { + if (aString === "[object Array]" && a.length !== b.length) { return false; } for (prop in a) { - aLength += 1; + if (a.hasOwnProperty(prop)) { + aLength += 1; - if (!(prop in b)) { - return false; - } + if (!(prop in b)) { + return false; + } - if (!deepEqual(a[prop], b[prop])) { - return false; + if (!deepEqual(a[prop], b[prop])) { + return false; + } } } for (prop in b) { - bLength += 1; + if (b.hasOwnProperty(prop)) { + bLength += 1; + } } - return aLength == bLength; + return aLength === bLength; }; sinon.functionName = function functionName(func) { @@ -1403,7 +1536,9 @@ var sinon = (function () { sinon.functionToString = function toString() { if (this.getCall && this.callCount) { - var thisValue, prop, i = this.callCount; + var thisValue, + prop; + var i = this.callCount; while (i--) { thisValue = this.getCall(i).thisValue; @@ -1436,12 +1571,14 @@ var sinon = (function () { }; sinon.getPropertyDescriptor = function getPropertyDescriptor(object, property) { - var proto = object, descriptor; + var proto = object; + var descriptor; + while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) { proto = Object.getPrototypeOf(proto); } return descriptor; - } + }; sinon.getConfig = function (custom) { var config = {}; @@ -1466,9 +1603,9 @@ var sinon = (function () { }; sinon.timesInWords = function timesInWords(count) { - return count == 1 && "once" || - count == 2 && "twice" || - count == 3 && "thrice" || + return count === 1 && "once" || + count === 2 && "twice" || + count === 3 && "thrice" || (count || 0) + " times"; }; @@ -1516,7 +1653,7 @@ var sinon = (function () { return sinon; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -1525,20 +1662,26 @@ var sinon = (function () { if (isAMD) { define(loadDependencies); - } else if (isNode) { - loadDependencies(require, module.exports); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (isNode) { + loadDependencies(require, module.exports, module); + return; + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { // Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug @@ -1572,13 +1715,15 @@ var sinon = (function () { return "8"; }, unique: function () { - return "9" + return "9"; } }; var result = []; for (var prop in obj) { - result.push(obj[prop]()); + if (obj.hasOwnProperty(prop)) { + result.push(obj[prop]()); + } } return result.join("") !== "0123456789"; })(); @@ -1592,8 +1737,8 @@ var sinon = (function () { * Returns the extended target */ function extend(target /*, sources */) { - var sources = Array.prototype.slice.call(arguments, 1), - source, i, prop; + var sources = Array.prototype.slice.call(arguments, 1); + var source, i, prop; for (i = 0; i < sources.length; i++) { source = sources[i]; @@ -1612,7 +1757,7 @@ var sinon = (function () { } return target; - }; + } sinon.extend = extend; return sinon.extend; @@ -1623,25 +1768,31 @@ var sinon = (function () { module.exports = makeApi(sinon); } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { function timesInWords(count) { @@ -1662,23 +1813,29 @@ var sinon = (function () { } function loadDependencies(require, exports, module) { - var sinon = require("./util/core"); - module.exports = makeApi(sinon); + var core = require("./util/core"); + module.exports = makeApi(core); } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js @@ -1691,8 +1848,8 @@ var sinon = (function () { * * Copyright (c) 2010-2014 Christian Johansen */ - -(function (sinon, formatio) { +(function (sinonGlobal) { + function makeApi(sinon) { function typeOf(value) { if (value === null) { @@ -1702,32 +1859,35 @@ var sinon = (function () { } 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 core = require("./util/core"); + module.exports = makeApi(core); } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); } }( - (typeof sinon == "object" && sinon || null), - (typeof formatio == "object" && formatio) + typeof sinon === "object" && sinon // eslint-disable-line no-undef )); /** @@ -1744,8 +1904,8 @@ var sinon = (function () { * * Copyright (c) 2012 Maximilian Antoni */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { function assertType(value, type, name) { var actual = sinon.typeOf(value); @@ -1769,57 +1929,27 @@ var sinon = (function () { 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; - }; + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + var exp = expectation[key]; + var act = actual[key]; + if (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; + } - var match = function (expectation, message) { + function match(expectation, message) { var m = sinon.create(matcher); var type = sinon.typeOf(expectation); switch (type) { @@ -1844,7 +1974,8 @@ var sinon = (function () { break; case "number": m.test = function (actual) { - return expectation == actual; + // we need type coercion here + return expectation == actual; // eslint-disable-line eqeqeq }; break; case "string": @@ -1881,6 +2012,36 @@ var sinon = (function () { m.message = "match(" + expectation + ")"; } return m; + } + + 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; }; match.isMatcher = isMatcher; @@ -1964,7 +2125,7 @@ var sinon = (function () { return match; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -1975,14 +2136,20 @@ var sinon = (function () { if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js @@ -1995,8 +2162,8 @@ var sinon = (function () { * * Copyright (c) 2010-2014 Christian Johansen */ - -(function (sinon, formatio) { +(function (sinonGlobal, formatio) { + function makeApi(sinon) { function valueFormatter(value) { return "" + value; @@ -2010,36 +2177,38 @@ var sinon = (function () { 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; - }; - + function getNodeFormatter() { try { var util = require("util"); } catch (e) { /* Node, but no util module - would be very old, but better safe than sorry */ } + function format(v) { + var isObjectWithNativeToString = typeof v === "object" && v.toString === Object.prototype.toString; + return isObjectWithNativeToString ? util.inspect(v) : v; + } + return util ? format : valueFormatter; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function", - formatter; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; + var formatter; if (isNode) { try { formatio = require("formatio"); - } catch (e) {} + } + catch (e) {} // eslint-disable-line no-empty } if (formatio) { - formatter = getFormatioFormatter() + formatter = getFormatioFormatter(); } else if (isNode) { formatter = getNodeFormatter(); } else { @@ -2055,21 +2224,25 @@ var sinon = (function () { module.exports = makeApi(sinon); } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); + } + + if (sinonGlobal) { + makeApi(sinonGlobal); } }( - (typeof sinon == "object" && sinon || null), - (typeof formatio == "object" && formatio) + typeof sinon === "object" && sinon, // eslint-disable-line no-undef + typeof formatio === "object" && formatio // eslint-disable-line no-undef )); /** @@ -2087,8 +2260,10 @@ var sinon = (function () { * Copyright (c) 2010-2013 Christian Johansen * Copyright (c) 2013 Maximilian Antoni */ +(function (sinonGlobal) { + + var slice = Array.prototype.slice; -(function (sinon) { function makeApi(sinon) { function throwYieldError(proxy, text, args) { var msg = sinon.functionName(proxy) + text; @@ -2098,8 +2273,6 @@ var sinon = (function () { throw new Error(msg); } - var slice = Array.prototype.slice; - var callProto = { calledOn: function calledOn(thisValue) { if (sinon.match && sinon.match.isMatcher(thisValue)) { @@ -2138,7 +2311,7 @@ var sinon = (function () { }, calledWithExactly: function calledWithExactly() { - return arguments.length == this.args.length && + return arguments.length === this.args.length && this.calledWith.apply(this, arguments); }, @@ -2191,7 +2364,7 @@ var sinon = (function () { this.args[pos].apply(thisValue, args); }, - yield: function () { + "yield": function () { this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0))); }, @@ -2222,17 +2395,26 @@ var sinon = (function () { "' since no callback was passed.", args); }, + getStackFrames: function () { + // Omit the error message and the two top stack frames in sinon itself: + return this.stack && this.stack.split("\n").slice(3); + }, + toString: function () { - var callStr = this.proxy.toString() + "("; + var callStr = this.proxy ? this.proxy.toString() + "(" : ""; var args = []; + if (!this.args) { + return ":("; + } + 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") { + if (typeof this.returnValue !== "undefined") { callStr += " => " + sinon.format(this.returnValue); } @@ -2243,6 +2425,10 @@ var sinon = (function () { callStr += "(" + this.exception.message + ")"; } } + if (this.stack) { + callStr += this.getStackFrames()[0].replace(/^\s*(?:at\s+|@)?/, " at "); + + } return callStr; } @@ -2250,7 +2436,7 @@ var sinon = (function () { callProto.invokeCallback = callProto.yield; - function createSpyCall(spy, thisValue, args, returnValue, exception, id) { + function createSpyCall(spy, thisValue, args, returnValue, exception, id, stack) { if (typeof id !== "number") { throw new TypeError("Call id is not a number"); } @@ -2261,6 +2447,7 @@ var sinon = (function () { proxyCall.returnValue = returnValue; proxyCall.exception = exception; proxyCall.callId = id; + proxyCall.stack = stack; return proxyCall; } @@ -2270,7 +2457,7 @@ var sinon = (function () { return createSpyCall; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -2282,14 +2469,20 @@ var sinon = (function () { if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend times_in_words.js @@ -2306,16 +2499,15 @@ var sinon = (function () { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { - +(function (sinonGlobal) { + 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") { + if (!property && typeof object === "function") { return spy.create(object); } @@ -2329,15 +2521,14 @@ var sinon = (function () { 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)); } + + return sinon.wrapMethod(object, property, spy.create(object[property])); } function matchingFake(fakes, args, strict) { if (!fakes) { - return; + return undefined; } for (var i = 0, l = fakes.length; i < l; i++) { @@ -2351,9 +2542,9 @@ var sinon = (function () { this.called = true; this.callCount += 1; this.notCalled = false; - this.calledOnce = this.callCount == 1; - this.calledTwice = this.callCount == 2; - this.calledThrice = this.callCount == 3; + this.calledOnce = this.callCount === 1; + this.calledTwice = this.callCount === 2; + this.calledThrice = this.callCount === 3; } function createCallProperties() { @@ -2368,7 +2559,7 @@ var sinon = (function () { // Retain the function length: var p; if (proxyLength) { - eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) + + eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) + // eslint-disable-line no-eval ") { return p.invoke(func, this, slice.call(arguments)); });"); } else { p = function proxy() { @@ -2406,6 +2597,7 @@ var sinon = (function () { this.thisValues = []; this.exceptions = []; this.callIds = []; + this.stacks = []; if (this.fakes) { for (var i = 0; i < this.fakes.length; i++) { this.fakes[i].reset(); @@ -2418,7 +2610,7 @@ var sinon = (function () { create: function create(func, spyLength) { var name; - if (typeof func != "function") { + if (typeof func !== "function") { func = function () { }; } else { name = sinon.functionName(func); @@ -2477,6 +2669,7 @@ var sinon = (function () { push.call(this.exceptions, exception); push.call(this.returnValues, returnValue); + push.call(this.stacks, new Error().stack); // Make return value and exception available in the calls: createCallProperties.call(this); @@ -2500,7 +2693,7 @@ var sinon = (function () { return sinon.spyCall(this, this.thisValues[i], this.args[i], this.returnValues[i], this.exceptions[i], - this.callIds[i]); + this.callIds[i], this.stacks[i]); }, getCalls: function () { @@ -2577,20 +2770,20 @@ var sinon = (function () { if (margs.length <= args.length && sinon.deepEqual(margs, args.slice(0, margs.length))) { - return !strict || margs.length == args.length; + return !strict || margs.length === args.length; } }, printf: function (format) { - var spy = this; + var spyInstance = 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); + if (typeof formatter === "function") { + return formatter.call(null, spyInstance, args); } else if (!isNaN(parseInt(specifyer, 10))) { return sinon.format(args[specifyer - 1]); } @@ -2674,19 +2867,19 @@ var sinon = (function () { }); spyApi.formatters = { - c: function (spy) { - return sinon.timesInWords(spy.callCount); + c: function (spyInstance) { + return sinon.timesInWords(spyInstance.callCount); }, - n: function (spy) { - return spy.toString(); + n: function (spyInstance) { + return spyInstance.toString(); }, - C: function (spy) { + C: function (spyInstance) { var calls = []; - for (var i = 0, l = spy.callCount; i < l; ++i) { - var stringifiedCall = " " + spy.getCall(i).toString(); + for (var i = 0, l = spyInstance.callCount; i < l; ++i) { + var stringifiedCall = " " + spyInstance.getCall(i).toString(); if (/\n/.test(calls[i - 1])) { stringifiedCall = "\n" + stringifiedCall; } @@ -2696,17 +2889,17 @@ var sinon = (function () { return calls.length > 0 ? "\n" + calls.join("\n") : ""; }, - t: function (spy) { + t: function (spyInstance) { var objects = []; - for (var i = 0, l = spy.callCount; i < l; ++i) { - push.call(objects, sinon.format(spy.thisValues[i])); + for (var i = 0, l = spyInstance.callCount; i < l; ++i) { + push.call(objects, sinon.format(spyInstance.thisValues[i])); } return objects.join(", "); }, - "*": function (spy, args) { + "*": function (spyInstance, args) { var formatted = []; for (var i = 0, l = args.length; i < l; ++i) { @@ -2725,28 +2918,34 @@ var sinon = (function () { return spy; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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"); + var core = require("./util/core"); require("./call"); require("./extend"); require("./times_in_words"); require("./format"); - module.exports = makeApi(sinon); + module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js @@ -2761,8 +2960,8 @@ var sinon = (function () { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + var slice = Array.prototype.slice; var join = Array.prototype.join; var useLeftMostCallback = -1; @@ -2771,17 +2970,19 @@ var sinon = (function () { var nextTick = (function () { if (typeof process === "object" && typeof process.nextTick === "function") { return process.nextTick; - } else if (typeof setImmediate === "function") { + } + + if (typeof setImmediate === "function") { return setImmediate; - } else { - return function (callback) { - setTimeout(callback, 0); - }; } + + return function (callback) { + setTimeout(callback, 0); + }; })(); function throwsException(error, message) { - if (typeof error == "string") { + if (typeof error === "string") { this.exception = new Error(message || ""); this.exception.name = error; } else if (!error) { @@ -2813,12 +3014,12 @@ var sinon = (function () { var callArgProp = behavior.callArgProp; for (var i = 0, l = argumentList.length; i < l; ++i) { - if (!callArgProp && typeof argumentList[i] == "function") { + if (!callArgProp && typeof argumentList[i] === "function") { return argumentList[i]; } if (callArgProp && argumentList[i] && - typeof argumentList[i][callArgProp] == "function") { + typeof argumentList[i][callArgProp] === "function") { return argumentList[i][callArgProp]; } } @@ -2851,10 +3052,10 @@ var sinon = (function () { } function callCallback(behavior, args) { - if (typeof behavior.callArgAt == "number") { + if (typeof behavior.callArgAt === "number") { var func = getCallback(behavior, args); - if (typeof func != "function") { + if (typeof func !== "function") { throw new TypeError(getCallbackError(behavior, func, args)); } @@ -2878,9 +3079,9 @@ var sinon = (function () { }, isPresent: function isPresent() { - return (typeof this.callArgAt == "number" || + return (typeof this.callArgAt === "number" || this.exception || - typeof this.returnArgAt == "number" || + typeof this.returnArgAt === "number" || this.returnThis || this.returnValueDefined); }, @@ -2890,7 +3091,7 @@ var sinon = (function () { if (this.exception) { throw this.exception; - } else if (typeof this.returnArgAt == "number") { + } else if (typeof this.returnArgAt === "number") { return args[this.returnArgAt]; } else if (this.returnThis) { return context; @@ -2916,12 +3117,15 @@ var sinon = (function () { }, 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."); + 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") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } @@ -2935,10 +3139,10 @@ var sinon = (function () { }, callsArgOn: function callsArgOn(pos, context) { - if (typeof pos != "number") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } - if (typeof context != "object") { + if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } @@ -2952,7 +3156,7 @@ var sinon = (function () { }, callsArgWith: function callsArgWith(pos) { - if (typeof pos != "number") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } @@ -2966,10 +3170,10 @@ var sinon = (function () { }, callsArgOnWith: function callsArgWith(pos, context) { - if (typeof pos != "number") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } - if (typeof context != "object") { + if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } @@ -3003,7 +3207,7 @@ var sinon = (function () { }, yieldsOn: function (context) { - if (typeof context != "object") { + if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } @@ -3027,7 +3231,7 @@ var sinon = (function () { }, yieldsToOn: function (prop, context) { - if (typeof context != "object") { + if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } @@ -3046,12 +3250,13 @@ var sinon = (function () { returns: function returns(value) { this.returnValue = value; this.returnValueDefined = true; + this.exception = undefined; return this; }, returnsArg: function returnsArg(pos) { - if (typeof pos != "number") { + if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } @@ -3067,19 +3272,19 @@ var sinon = (function () { } }; + function createAsyncVersion(syncFnName) { + return function () { + var result = this[syncFnName].apply(this, arguments); + this.callbackAsync = true; + return result; + }; + } + // 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); + if (proto.hasOwnProperty(method) && method.match(/^(callsArg|yields)/) && !method.match(/Async/)) { + proto[method + "Async"] = createAsyncVersion(method); } } @@ -3087,7 +3292,7 @@ var sinon = (function () { return proto; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -3098,20 +3303,106 @@ var sinon = (function () { if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); + +/** + * @depend util/core.js + */ +(function (sinonGlobal) { + + function makeApi(sinon) { + function walkInternal(obj, iterator, context, originalObj, seen) { + var proto, prop; + + if (typeof Object.getOwnPropertyNames !== "function") { + // We explicitly want to enumerate through all of the prototype's properties + // in this case, therefore we deliberately leave out an own property check. + /* eslint-disable guard-for-in */ + for (prop in obj) { + iterator.call(context, obj[prop], prop, obj); + } + /* eslint-enable guard-for-in */ + + return; + } + + Object.getOwnPropertyNames(obj).forEach(function (k) { + if (!seen[k]) { + seen[k] = true; + var target = typeof Object.getOwnPropertyDescriptor(obj, k).get === "function" ? + originalObj : obj; + iterator.call(context, target[k], k, target); + } + }); + + proto = Object.getPrototypeOf(obj); + if (proto) { + walkInternal(proto, iterator, context, originalObj, seen); + } + } + + /* Public: walks the prototype chain of an object and iterates over every own property + * name encountered. The iterator is called in the same fashion that Array.prototype.forEach + * works, where it is passed the value, key, and own object as the 1st, 2nd, and 3rd positional + * argument, respectively. In cases where Object.getOwnPropertyNames is not available, walk will + * default to using a simple for..in loop. + * + * obj - The object to walk the prototype chain for. + * iterator - The function to be called on each pass of the walk. + * context - (Optional) When given, the iterator will be called with this object as the receiver. + */ + function walk(obj, iterator, context) { + return walkInternal(obj, iterator, context, obj, {}); + } + + sinon.walk = walk; + return sinon.walk; + } + + 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); + return; + } + + if (isNode) { + loadDependencies(require, module.exports, module); + return; + } + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js * @depend extend.js * @depend spy.js * @depend behavior.js + * @depend walk.js */ /** * Stub functions @@ -3121,18 +3412,18 @@ var sinon = (function () { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { function stub(object, property, func) { - if (!!func && typeof func != "function" && typeof func != "object") { + 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") { + if (typeof func === "function") { wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; } else { wrapper = func; @@ -3145,7 +3436,7 @@ var sinon = (function () { } } else { var stubLength = 0; - if (typeof object == "object" && typeof object[property] == "function") { + if (typeof object === "object" && typeof object[property] === "function") { stubLength = object[property].length; } wrapper = stub.create(stubLength); @@ -3155,12 +3446,18 @@ var sinon = (function () { return sinon.stub.create(); } - if (typeof property === "undefined" && typeof object == "object") { - for (var prop in object) { - if (typeof sinon.getPropertyDescriptor(object, prop).value === "function") { + if (typeof property === "undefined" && typeof object === "object") { + sinon.walk(object || {}, function (value, prop, propOwner) { + // we don't want to stub things like toString(), valueOf(), etc. so we only stub if the object + // is not Object.prototype + if ( + propOwner !== Object.prototype && + prop !== "constructor" && + typeof sinon.getPropertyDescriptor(propOwner, prop).value === "function" + ) { stub(object, prop); } - } + }); return object; } @@ -3168,18 +3465,23 @@ var sinon = (function () { return sinon.wrapMethod(object, property, wrapper); } - function getDefaultBehavior(stub) { - return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub); + + /*eslint-disable no-use-before-define*/ + function getParentBehaviour(stubInstance) { + return (stubInstance.parent && getCurrentBehavior(stubInstance.parent)); } - function getParentBehaviour(stub) { - return (stub.parent && getCurrentBehavior(stub.parent)); + function getDefaultBehavior(stubInstance) { + return stubInstance.defaultBehavior || + getParentBehaviour(stubInstance) || + sinon.behavior.create(stubInstance); } - function getCurrentBehavior(stub) { - var behavior = stub.behaviors[stub.callCount - 1]; - return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub); + function getCurrentBehavior(stubInstance) { + var behavior = stubInstance.behaviors[stubInstance.callCount - 1]; + return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stubInstance); } + /*eslint-enable no-use-before-define*/ var uuid = 0; @@ -3243,19 +3545,21 @@ var sinon = (function () { } }; + function createBehavior(behaviorMethod) { + return function () { + this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); + this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); + return this; + }; + } + 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)); + method !== "create" && + method !== "withArgs" && + method !== "invoke") { + proto[method] = createBehavior(method); } } @@ -3265,27 +3569,33 @@ var sinon = (function () { return stub; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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"); + var core = require("./util/core"); require("./behavior"); require("./spy"); require("./extend"); - module.exports = makeApi(sinon); + module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend times_in_words.js @@ -3305,8 +3615,8 @@ var sinon = (function () { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { var push = [].push; var match = sinon.match; @@ -3333,6 +3643,19 @@ var sinon = (function () { } } + function arrayEquals(arr1, arr2, compareLength) { + if (compareLength && (arr1.length !== arr2.length)) { + return false; + } + + for (var i = 0, l = arr1.length; i < l; i++) { + if (!sinon.deepEqual(arr1[i], arr2[i])) { + return false; + } + } + return true; + } + sinon.extend(mock, { create: function create(object) { if (!object) { @@ -3377,7 +3700,7 @@ var sinon = (function () { var object = this.object; each(this.proxies, function (proxy) { - if (typeof object[proxy].restore == "function") { + if (typeof object[proxy].restore === "function") { object[proxy].restore(); } }); @@ -3385,7 +3708,8 @@ var sinon = (function () { verify: function verify() { var expectations = this.expectations || {}; - var messages = [], met = []; + var messages = []; + var met = []; each(this.proxies, function (proxy) { each(expectations[proxy], function (expectation) { @@ -3409,31 +3733,44 @@ var sinon = (function () { }, invokeMethod: function invokeMethod(method, thisValue, args) { - var expectations = this.expectations && this.expectations[method]; - var length = expectations && expectations.length || 0, i; + var expectations = this.expectations && this.expectations[method] ? this.expectations[method] : []; + var expectationsWithMatchingArgs = []; + var currentArgs = args || []; + var i, available; + + for (i = 0; i < expectations.length; i += 1) { + var expectedArgs = expectations[i].expectedArguments || []; + if (arrayEquals(expectedArgs, currentArgs, expectations[i].expectsExactArgCount)) { + expectationsWithMatchingArgs.push(expectations[i]); + } + } - for (i = 0; i < length; i += 1) { - if (!expectations[i].met() && - expectations[i].allowsCall(thisValue, args)) { - return expectations[i].apply(thisValue, args); + for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) { + if (!expectationsWithMatchingArgs[i].met() && + expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) { + return expectationsWithMatchingArgs[i].apply(thisValue, args); } } - var messages = [], available, exhausted = 0; + var messages = []; + var exhausted = 0; - for (i = 0; i < length; i += 1) { - if (expectations[i].allowsCall(thisValue, args)) { - available = available || expectations[i]; + for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) { + if (expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) { + available = available || expectationsWithMatchingArgs[i]; } else { exhausted += 1; } - push.call(messages, " " + expectations[i].toString()); } - if (exhausted === 0) { + if (available && exhausted === 0) { return available.apply(thisValue, args); } + for (i = 0; i < expectations.length; i += 1) { + push.call(messages, " " + expectations[i].toString()); + } + messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ proxy: method, args: args @@ -3447,28 +3784,28 @@ var sinon = (function () { var slice = Array.prototype.slice; function callCountInWords(callCount) { - if (callCount == 0) { + if (callCount === 0) { return "never called"; - } else { - return "called " + times(callCount); } + + return "called " + times(callCount); } function expectedCallCountInWords(expectation) { var min = expectation.minCalls; var max = expectation.maxCalls; - if (typeof min == "number" && typeof max == "number") { + if (typeof min === "number" && typeof max === "number") { var str = times(min); - if (min != max) { + if (min !== max) { str = "at least " + str + " and at most " + times(max); } return str; } - if (typeof min == "number") { + if (typeof min === "number") { return "at least " + times(min); } @@ -3476,24 +3813,22 @@ var sinon = (function () { } function receivedMinCalls(expectation) { - var hasMinLimit = typeof expectation.minCalls == "number"; + var hasMinLimit = typeof expectation.minCalls === "number"; return !hasMinLimit || expectation.callCount >= expectation.minCalls; } function receivedMaxCalls(expectation) { - if (typeof expectation.maxCalls != "number") { + if (typeof expectation.maxCalls !== "number") { return false; } - return expectation.callCount == expectation.maxCalls; + return expectation.callCount === expectation.maxCalls; } function verifyMatcher(possibleMatcher, arg) { - if (match && match.isMatcher(possibleMatcher)) { - return possibleMatcher.test(arg); - } else { - return true; - } + var isMatcher = match && match.isMatcher(possibleMatcher); + + return isMatcher && possibleMatcher.test(arg) || true; } sinon.expectation = { @@ -3515,7 +3850,7 @@ var sinon = (function () { }, atLeast: function atLeast(num) { - if (typeof num != "number") { + if (typeof num !== "number") { throw new TypeError("'" + num + "' is not number"); } @@ -3530,7 +3865,7 @@ var sinon = (function () { }, atMost: function atMost(num) { - if (typeof num != "number") { + if (typeof num !== "number") { throw new TypeError("'" + num + "' is not number"); } @@ -3561,7 +3896,7 @@ var sinon = (function () { }, exactly: function exactly(num) { - if (typeof num != "number") { + if (typeof num !== "number") { throw new TypeError("'" + num + "' is not a number"); } @@ -3599,7 +3934,7 @@ var sinon = (function () { } if (this.expectsExactArgCount && - args.length != this.expectedArguments.length) { + args.length !== this.expectedArguments.length) { sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + "), expected " + sinon.format(this.expectedArguments)); } @@ -3638,7 +3973,7 @@ var sinon = (function () { } if (this.expectsExactArgCount && - args.length != this.expectedArguments.length) { + args.length !== this.expectedArguments.length) { return false; } @@ -3720,7 +4055,7 @@ var sinon = (function () { return mock; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -3738,14 +4073,20 @@ var sinon = (function () { if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js @@ -3761,8 +4102,8 @@ var sinon = (function () { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + var push = [].push; var hasOwnProperty = Object.prototype.hasOwnProperty; @@ -3778,7 +4119,7 @@ var sinon = (function () { var fakes = getFakes(fakeCollection); for (var i = 0, l = fakes.length; i < l; i += 1) { - if (typeof fakes[i][method] == "function") { + if (typeof fakes[i][method] === "function") { fakes[i][method](); } } @@ -3836,7 +4177,7 @@ var sinon = (function () { if (property) { var original = object[property]; - if (typeof original != "function") { + if (typeof original !== "function") { if (!hasOwnProperty.call(object, property)) { throw new TypeError("Cannot stub non-existent own property " + property); } @@ -3850,7 +4191,7 @@ var sinon = (function () { }); } } - if (!property && !!object && typeof object == "object") { + if (!property && !!object && typeof object === "object") { var stubbedObj = sinon.stub.apply(sinon, arguments); for (var prop in stubbedObj) { @@ -3892,7 +4233,7 @@ var sinon = (function () { return collection; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -3905,16 +4246,20 @@ var sinon = (function () { if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); -/*global lolex */ + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * Fake timer API @@ -3933,17 +4278,15 @@ var sinon = (function () { * * Copyright (c) 2010-2013 Christian Johansen */ - -if (typeof sinon == "undefined") { - var sinon = {}; -} - -(function (global) { - function makeApi(sinon, lol) { +(function () { + + function makeApi(s, lol) { + /*global lolex */ var llx = typeof lolex !== "undefined" ? lolex : lol; - sinon.useFakeTimers = function () { - var now, methods = Array.prototype.slice.call(arguments); + s.useFakeTimers = function () { + var now; + var methods = Array.prototype.slice.call(arguments); if (typeof methods[0] === "string") { now = 0; @@ -3956,13 +4299,13 @@ if (typeof sinon == "undefined") { return clock; }; - sinon.clock = { + s.clock = { create: function (now) { return llx.createClock(now); } }; - sinon.timers = { + s.timers = { setTimeout: setTimeout, clearTimeout: clearTimeout, setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), @@ -3973,13 +4316,13 @@ if (typeof sinon == "undefined") { }; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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; + var core = require("./core"); + makeApi(core, lolex); + module.exports = core; } if (isAMD) { @@ -3987,9 +4330,9 @@ if (typeof sinon == "undefined") { } else if (isNode) { loadDependencies(require, module.exports, module, require("lolex")); } else { - makeApi(sinon); + makeApi(sinon); // eslint-disable-line no-undef } -}(typeof global != "undefined" && typeof global !== "function" ? global : this)); +}()); /** * Minimal Event interface implementation @@ -4003,12 +4346,12 @@ if (typeof sinon == "undefined") { * * Copyright (c) 2011 Sven Fuchs, Christian Johansen */ - -if (typeof sinon == "undefined") { +if (typeof sinon === "undefined") { this.sinon = {}; } (function () { + var push = [].push; function makeApi(sinon) { @@ -4040,7 +4383,7 @@ if (typeof sinon == "undefined") { sinon.ProgressEvent.prototype = new sinon.Event(); - sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; + sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; sinon.CustomEvent = function CustomEvent(type, customData, target) { this.initEvent(type, false, false, target); @@ -4049,7 +4392,7 @@ if (typeof sinon == "undefined") { sinon.CustomEvent.prototype = new sinon.Event(); - sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; + sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; sinon.EventTarget = { addEventListener: function addEventListener(event, listener) { @@ -4062,7 +4405,7 @@ if (typeof sinon == "undefined") { var listeners = this.eventListeners && this.eventListeners[event] || []; for (var i = 0, l = listeners.length; i < l; ++i) { - if (listeners[i] == listener) { + if (listeners[i] === listener) { return listeners.splice(i, 1); } } @@ -4073,7 +4416,7 @@ if (typeof sinon == "undefined") { var listeners = this.eventListeners && this.eventListeners[type] || []; for (var i = 0; i < listeners.length; i++) { - if (typeof listeners[i] == "function") { + if (typeof listeners[i] === "function") { listeners[i].call(this, event); } else { listeners[i].handleEvent(event); @@ -4085,7 +4428,7 @@ if (typeof sinon == "undefined") { }; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require) { @@ -4098,7 +4441,7 @@ if (typeof sinon == "undefined") { } else if (isNode) { loadDependencies(require); } else { - makeApi(sinon); + makeApi(sinon); // eslint-disable-line no-undef } }()); @@ -4113,8 +4456,8 @@ if (typeof sinon == "undefined") { * * Copyright (c) 2010-2014 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + // 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 @@ -4127,22 +4470,32 @@ if (typeof sinon == "undefined") { function logError(label, err) { var msg = label + " threw exception: "; + function throwLoggedError() { + err.message = msg + err.message; + throw err; + } + 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); - }; + if (logError.useImmediateExceptions) { + throwLoggedError(); + } else { + logError.setTimeout(throwLoggedError, 0); + } + } + + // When set to true, any errors logged will be thrown immediately; + // If set to false, the errors will be thrown in separate execution frame. + logError.useImmediateExceptions = false; // wrap realSetTimeout with something we can stub in tests logError.setTimeout = function (func, timeout) { realSetTimeout(func, timeout); - } + }; var exports = {}; exports.log = sinon.log = log; @@ -4156,19 +4509,25 @@ if (typeof sinon == "undefined") { module.exports = makeApi(sinon); } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend core.js @@ -4180,16 +4539,31 @@ if (typeof sinon == "undefined") { * Fake XDomainRequest object */ -if (typeof sinon == "undefined") { - this.sinon = {}; +/** + * Returns the global to prevent assigning values to 'this' when this is undefined. + * This can occur when files are interpreted by node in strict mode. + * @private + */ +function getGlobal() { + + return typeof window !== "undefined" ? window : global; +} + +if (typeof sinon === "undefined") { + if (typeof this === "undefined") { + getGlobal().sinon = {}; + } else { + 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; + xdr.supportsXDR = typeof xdr.GlobalXDomainRequest !== "undefined"; + xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; function makeApi(sinon) { sinon.xdr = xdr; @@ -4201,32 +4575,32 @@ if (typeof sinon == "undefined") { this.status = 0; this.timeout = null; - if (typeof FakeXDomainRequest.onCreate == "function") { + if (typeof FakeXDomainRequest.onCreate === "function") { FakeXDomainRequest.onCreate(this); } } - function verifyState(xdr) { - if (xdr.readyState !== FakeXDomainRequest.OPENED) { + function verifyState(x) { + if (x.readyState !== FakeXDomainRequest.OPENED) { throw new Error("INVALID_STATE_ERR"); } - if (xdr.sendFlag) { + if (x.sendFlag) { throw new Error("INVALID_STATE_ERR"); } } - function verifyRequestSent(xdr) { - if (xdr.readyState == FakeXDomainRequest.UNSENT) { + function verifyRequestSent(x) { + if (x.readyState === FakeXDomainRequest.UNSENT) { throw new Error("Request not sent"); } - if (xdr.readyState == FakeXDomainRequest.DONE) { + if (x.readyState === FakeXDomainRequest.DONE) { throw new Error("Request done"); } } function verifyResponseBodyType(body) { - if (typeof body != "string") { + if (typeof body !== "string") { var error = new Error("Attempted to respond to fake XDomainRequest with " + body + ", which is not a string."); error.name = "InvalidBodyException"; @@ -4261,18 +4635,18 @@ if (typeof sinon == "undefined") { break; case FakeXDomainRequest.DONE: if (this.isTimeout) { - eventName = "ontimeout" + eventName = "ontimeout"; } else if (this.errorFlag || (this.status < 200 || this.status > 299)) { eventName = "onerror"; } else { - eventName = "onload" + eventName = "onload"; } break; } // raising event (if defined) if (eventName) { - if (typeof this[eventName] == "function") { + if (typeof this[eventName] === "function") { try { this[eventName](); } catch (e) { @@ -4294,7 +4668,7 @@ if (typeof sinon == "undefined") { this.sendFlag = true; this.readyStateChange(FakeXDomainRequest.OPENED); - if (typeof this.onSend == "function") { + if (typeof this.onSend === "function") { this.onSend(this); } }, @@ -4331,7 +4705,7 @@ if (typeof sinon == "undefined") { // 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.status = typeof status === "number" ? status : 200; this.setResponseBody(body || ""); }, @@ -4372,7 +4746,7 @@ if (typeof sinon == "undefined") { sinon.FakeXDomainRequest = FakeXDomainRequest; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -4389,7 +4763,7 @@ if (typeof sinon == "undefined") { } else if (isNode) { loadDependencies(require, module.exports, module); } else { - makeApi(sinon); + makeApi(sinon); // eslint-disable-line no-undef } })(typeof global !== "undefined" ? global : self); @@ -4407,24 +4781,37 @@ if (typeof sinon == "undefined") { * * Copyright (c) 2010-2013 Christian Johansen */ +(function (sinonGlobal, global) { + + function getWorkingXHR(globalScope) { + var supportsXHR = typeof globalScope.XMLHttpRequest !== "undefined"; + if (supportsXHR) { + return globalScope.XMLHttpRequest; + } -(function (global) { + var supportsActiveX = typeof globalScope.ActiveXObject !== "undefined"; + if (supportsActiveX) { + return function () { + return new globalScope.ActiveXObject("MSXML2.XMLHTTP.3.0"); + }; + } + + return false; + } var supportsProgress = typeof ProgressEvent !== "undefined"; var supportsCustomEvent = typeof CustomEvent !== "undefined"; var supportsFormData = typeof FormData !== "undefined"; + var supportsArrayBuffer = typeof ArrayBuffer !== "undefined"; + var supportsBlob = typeof Blob === "function"; 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.supportsActiveX = typeof sinonXhr.GlobalActiveXObject !== "undefined"; + sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest !== "undefined"; + sinonXhr.workingXHR = getWorkingXHR(global); sinonXhr.supportsCORS = sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest()); - /*jsl:ignore*/ var unsafeHeaders = { "Accept-Charset": true, "Accept-Encoding": true, @@ -4445,7 +4832,41 @@ if (typeof sinon == "undefined") { "User-Agent": true, Via: true }; - /*jsl:end*/ + + // 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); + } + }; // Note that for FakeXMLHttpRequest to work pre ES5 // we lose some of the alignment with the spec. @@ -4471,7 +4892,7 @@ if (typeof sinon == "undefined") { xhr.addEventListener(eventName, function (event) { var listener = xhr["on" + eventName]; - if (listener && typeof listener == "function") { + if (listener && typeof listener === "function") { listener.call(this, event); } }); @@ -4481,46 +4902,11 @@ if (typeof sinon == "undefined") { addEventListener(events[i]); } - if (typeof FakeXMLHttpRequest.onCreate == "function") { + 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"); @@ -4535,7 +4921,7 @@ if (typeof sinon == "undefined") { header = header.toLowerCase(); for (var h in headers) { - if (h.toLowerCase() == header) { + if (h.toLowerCase() === header) { return h; } } @@ -4576,11 +4962,12 @@ if (typeof sinon == "undefined") { FakeXMLHttpRequest.filters = []; FakeXMLHttpRequest.addFilter = function addFilter(fn) { - this.filters.push(fn) + this.filters.push(fn); }; var IE6Re = /MSIE 6/; FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) { - var xhr = new sinonXhr.workingXHR(); + var xhr = new sinonXhr.workingXHR(); // eslint-disable-line new-cap + each([ "open", "setRequestHeader", @@ -4600,7 +4987,7 @@ if (typeof sinon == "undefined") { var copyAttrs = function (args) { each(args, function (attr) { try { - fakeXhr[attr] = xhr[attr] + fakeXhr[attr] = xhr[attr]; } catch (e) { if (!IE6Re.test(navigator.userAgent)) { throw e; @@ -4628,9 +5015,12 @@ if (typeof sinon == "undefined") { if (xhr.addEventListener) { for (var event in fakeXhr.eventListeners) { if (fakeXhr.eventListeners.hasOwnProperty(event)) { + + /*eslint-disable no-loop-func*/ each(fakeXhr.eventListeners[event], function (handler) { xhr.addEventListener(event, handler); }); + /*eslint-enable no-loop-func*/ } } xhr.addEventListener("readystatechange", stateChange); @@ -4642,25 +5032,25 @@ if (typeof sinon == "undefined") { FakeXMLHttpRequest.useFilters = false; function verifyRequestOpened(xhr) { - if (xhr.readyState != FakeXMLHttpRequest.OPENED) { + if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { throw new Error("INVALID_STATE_ERR - " + xhr.readyState); } } function verifyRequestSent(xhr) { - if (xhr.readyState == FakeXMLHttpRequest.DONE) { + if (xhr.readyState === FakeXMLHttpRequest.DONE) { throw new Error("Request done"); } } function verifyHeadersReceived(xhr) { - if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { + if (xhr.async && xhr.readyState !== FakeXMLHttpRequest.HEADERS_RECEIVED) { throw new Error("No headers received"); } } function verifyResponseBodyType(body) { - if (typeof body != "string") { + if (typeof body !== "string") { var error = new Error("Attempted to respond to fake XMLHttpRequest with " + body + ", which is not a string."); error.name = "InvalidBodyException"; @@ -4668,19 +5058,78 @@ if (typeof sinon == "undefined") { } } - FakeXMLHttpRequest.parseXML = function parseXML(text) { - var xmlDoc; + function convertToArrayBuffer(body) { + var buffer = new ArrayBuffer(body.length); + var view = new Uint8Array(buffer); + for (var i = 0; i < body.length; i++) { + var charCode = body.charCodeAt(i); + if (charCode >= 256) { + throw new TypeError("arraybuffer or blob responseTypes require binary string, " + + "invalid character " + body[i] + " found."); + } + view[i] = charCode; + } + return buffer; + } + + function isXmlContentType(contentType) { + return !contentType || /(text\/xml)|(application\/xml)|(\+xml)/.test(contentType); + } - if (typeof DOMParser != "undefined") { - var parser = new DOMParser(); - xmlDoc = parser.parseFromString(text, "text/xml"); + function convertResponseBody(responseType, contentType, body) { + if (responseType === "" || responseType === "text") { + return body; + } else if (supportsArrayBuffer && responseType === "arraybuffer") { + return convertToArrayBuffer(body); + } else if (responseType === "json") { + try { + return JSON.parse(body); + } catch (e) { + // Return parsing failure as null + return null; + } + } else if (supportsBlob && responseType === "blob") { + var blobOptions = {}; + if (contentType) { + blobOptions.type = contentType; + } + return new Blob([convertToArrayBuffer(body)], blobOptions); + } else if (responseType === "document") { + if (isXmlContentType(contentType)) { + return FakeXMLHttpRequest.parseXML(body); + } + return null; + } + throw new Error("Invalid responseType " + responseType); + } + + function clearResponse(xhr) { + if (xhr.responseType === "" || xhr.responseType === "text") { + xhr.response = xhr.responseText = ""; } else { - xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); - xmlDoc.async = "false"; - xmlDoc.loadXML(text); + xhr.response = xhr.responseText = null; + } + xhr.responseXML = null; + } + + FakeXMLHttpRequest.parseXML = function parseXML(text) { + // Treat empty string as parsing failure + if (text !== "") { + try { + if (typeof DOMParser !== "undefined") { + var parser = new DOMParser(); + return parser.parseFromString(text, "text/xml"); + } + var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async = "false"; + xmlDoc.loadXML(text); + return xmlDoc; + } catch (e) { + // Unable to parse XML - no biggie + } } - return xmlDoc; + return null; }; FakeXMLHttpRequest.statusCodes = { @@ -4737,19 +5186,17 @@ if (typeof sinon == "undefined") { open: function open(method, url, async, username, password) { this.method = method; this.url = url; - this.async = typeof async == "boolean" ? async : true; + 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; + clearResponse(this); this.requestHeaders = {}; this.sendFlag = false; if (FakeXMLHttpRequest.useFilters === true) { var xhrArgs = arguments; var defake = some(FakeXMLHttpRequest.filters, function (filter) { - return filter.apply(this, xhrArgs) + return filter.apply(this, xhrArgs); }); if (defake) { return FakeXMLHttpRequest.defake(this, arguments); @@ -4761,9 +5208,11 @@ if (typeof sinon == "undefined") { readyStateChange: function readyStateChange(state) { this.readyState = state; - if (typeof this.onreadystatechange == "function") { + var readyStateChangeEvent = new sinon.Event("readystatechange", false, false, this); + + if (typeof this.onreadystatechange === "function") { try { - this.onreadystatechange(); + this.onreadystatechange(readyStateChangeEvent); } catch (e) { sinon.logError("Fake XHR onreadystatechange handler", e); } @@ -4781,7 +5230,7 @@ if (typeof sinon == "undefined") { break; } - this.dispatchEvent(new sinon.Event("readystatechange")); + this.dispatchEvent(readyStateChangeEvent); }, setRequestHeader: function setRequestHeader(header, value) { @@ -4834,10 +5283,10 @@ if (typeof sinon == "undefined") { this.errorFlag = false; this.sendFlag = this.async; - this.response = this.responseType === "json" ? null : ""; + clearResponse(this); this.readyStateChange(FakeXMLHttpRequest.OPENED); - if (typeof this.onSend == "function") { + if (typeof this.onSend === "function") { this.onSend(this); } @@ -4846,8 +5295,7 @@ if (typeof sinon == "undefined") { abort: function abort() { this.aborted = true; - this.responseText = null; - this.response = this.responseType === "json" ? null : ""; + clearResponse(this); this.errorFlag = true; this.requestHeaders = {}; this.responseHeaders = {}; @@ -4903,37 +5351,39 @@ if (typeof sinon == "undefined") { verifyRequestSent(this); verifyHeadersReceived(this); verifyResponseBodyType(body); + var contentType = this.getResponseHeader("Content-Type"); - var chunkSize = this.chunkSize || 10; - var index = 0; - this.responseText = ""; + var isTextResponse = this.responseType === "" || this.responseType === "text"; + clearResponse(this); + if (this.async) { + var chunkSize = this.chunkSize || 10; + var index = 0; - do { - if (this.async) { + do { this.readyStateChange(FakeXMLHttpRequest.LOADING); - } - - this.responseText += body.substring(index, index + chunkSize); - index += chunkSize; - } while (index < body.length); - var type = this.getResponseHeader("Content-Type"); + if (isTextResponse) { + this.responseText = this.response += body.substring(index, index + chunkSize); + } + index += chunkSize; + } while (index < body.length); + } - 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 = convertResponseBody(this.responseType, contentType, body); + if (isTextResponse) { + this.responseText = this.response; } - this.response = this.responseType === "json" ? JSON.parse(this.responseText) : this.responseText; + if (this.responseType === "document") { + this.responseXML = this.response; + } else if (this.responseType === "" && isXmlContentType(contentType)) { + this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); + } this.readyStateChange(FakeXMLHttpRequest.DONE); }, respond: function respond(status, headers, body) { - this.status = typeof status == "number" ? status : 200; + this.status = typeof status === "number" ? status : 200; this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; this.setResponseHeaders(headers || {}); this.setResponseBody(body || ""); @@ -4988,7 +5438,7 @@ if (typeof sinon == "undefined") { if (sinonXhr.supportsActiveX) { global.ActiveXObject = function ActiveXObject(objId) { - if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { + if (objId === "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { return new FakeXMLHttpRequest(); } @@ -5003,7 +5453,7 @@ if (typeof sinon == "undefined") { sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -5017,15 +5467,21 @@ if (typeof sinon == "undefined") { if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (typeof sinon === "undefined") { return; - } else { - makeApi(sinon); } -})(typeof global !== "undefined" ? global : self); + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon, // eslint-disable-line no-undef + typeof global !== "undefined" ? global : self +)); /** * @depend fake_xdomain_request.js @@ -5044,28 +5500,18 @@ if (typeof sinon == "undefined") { * * 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]") { + if (Object.prototype.toString.call(handler) !== "[object Array]") { response = [200, {}, handler]; } - if (typeof response[2] != "string") { + if (typeof response[2] !== "string") { throw new TypeError("Fake server response body should be string, but was " + typeof response[2]); } @@ -5078,9 +5524,9 @@ if (typeof sinon == "undefined") { function matchOne(response, reqMethod, reqUrl) { var rmeth = response.method; - var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); + var matchMethod = !rmeth || rmeth.toLowerCase() === reqMethod.toLowerCase(); var url = response.url; - var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); + var matchUrl = !url || url === reqUrl || (typeof url.test === "function" && url.test(reqUrl)); return matchMethod && matchUrl; } @@ -5093,9 +5539,9 @@ if (typeof sinon == "undefined") { } if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { - if (typeof response.response == "function") { + if (typeof response.response === "function") { var ru = response.url; - var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []); + var args = [request].concat(ru && typeof ru.exec === "function" ? ru.exec(requestUrl).slice(1) : []); return response.response.apply(response, args); } @@ -5107,8 +5553,9 @@ if (typeof sinon == "undefined") { function makeApi(sinon) { sinon.fakeServer = { - create: function () { - var server = create(this); + create: function (config) { + var server = sinon.create(this); + server.configure(config); if (!sinon.xhr.supportsCORS) { this.xhr = sinon.useFakeXDomainRequest(); } else { @@ -5122,7 +5569,22 @@ if (typeof sinon == "undefined") { return server; }, + configure: function (config) { + var whitelist = { + "autoRespond": true, + "autoRespondAfter": true, + "respondImmediately": true, + "fakeHTTPMethods": true + }; + var setting; + config = config || {}; + for (setting in config) { + if (whitelist.hasOwnProperty(setting) && config.hasOwnProperty(setting)) { + this[setting] = config[setting]; + } + } + }, addRequest: function addRequest(xhrObj) { var server = this; push.call(this.requests, xhrObj); @@ -5146,7 +5608,7 @@ if (typeof sinon == "undefined") { 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 matches ? matches[1] : request.method; } return request.method; @@ -5167,14 +5629,14 @@ if (typeof sinon == "undefined") { log: function log(response, request) { var str; - str = "Request:\n" + sinon.format(request) + "\n\n"; + 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") { + if (arguments.length === 1 && typeof method !== "function") { this.response = responseArray(method); return; } @@ -5183,12 +5645,12 @@ if (typeof sinon == "undefined") { this.responses = []; } - if (arguments.length == 1) { + if (arguments.length === 1) { body = method; url = method = null; } - if (arguments.length == 2) { + if (arguments.length === 2) { body = url; url = method; method = null; @@ -5197,7 +5659,7 @@ if (typeof sinon == "undefined") { push.call(this.responses, { method: method, url: url, - response: typeof body == "function" ? body : responseArray(body) + response: typeof body === "function" ? body : responseArray(body) }); }, @@ -5208,10 +5670,9 @@ if (typeof sinon == "undefined") { var queue = this.queue || []; var requests = queue.splice(0, queue.length); - var request; - while (request = requests.shift()) { - this.processRequest(request); + for (var i = 0; i < requests.length; i++) { + this.processRequest(requests[i]); } }, @@ -5232,7 +5693,7 @@ if (typeof sinon == "undefined") { } } - if (request.readyState != 4) { + if (request.readyState !== 4) { this.log(response, request); request.respond(response[0], response[1], response[2]); @@ -5248,7 +5709,7 @@ if (typeof sinon == "undefined") { }; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -5265,7 +5726,7 @@ if (typeof sinon == "undefined") { } else if (isNode) { loadDependencies(require, module.exports, module); } else { - makeApi(sinon); + makeApi(sinon); // eslint-disable-line no-undef } }()); @@ -5287,8 +5748,8 @@ if (typeof sinon == "undefined") { * * Copyright (c) 2010-2013 Christian Johansen */ - (function () { + function makeApi(sinon) { function Server() {} Server.prototype = sinon.fakeServer; @@ -5297,7 +5758,7 @@ if (typeof sinon == "undefined") { sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { if (xhr.async) { - if (typeof setTimeout.clock == "object") { + if (typeof setTimeout.clock === "object") { this.clock = setTimeout.clock; } else { this.clock = sinon.useFakeTimers(); @@ -5351,7 +5812,7 @@ if (typeof sinon == "undefined") { }; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require) { @@ -5366,7 +5827,7 @@ if (typeof sinon == "undefined") { } else if (isNode) { loadDependencies(require); } else { - makeApi(sinon); + makeApi(sinon); // eslint-disable-line no-undef } }()); @@ -5386,8 +5847,8 @@ if (typeof sinon == "undefined") { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function () { +(function (sinonGlobal) { + function makeApi(sinon) { var push = [].push; @@ -5408,7 +5869,7 @@ if (typeof sinon == "undefined") { var sandbox = sinon.create(sinon.sandbox); if (config.useFakeServer) { - if (typeof config.useFakeServer == "object") { + if (typeof config.useFakeServer === "object") { sandbox.serverPrototype = config.useFakeServer; } @@ -5416,7 +5877,7 @@ if (typeof sinon == "undefined") { } if (config.useFakeTimers) { - if (typeof config.useFakeTimers == "object") { + if (typeof config.useFakeTimers === "object") { sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); } else { sandbox.useFakeTimers(); @@ -5486,12 +5947,14 @@ if (typeof sinon == "undefined") { sandbox.args = sandbox.args || []; sandbox.injectedKeys = []; sandbox.injectInto = config.injectInto; - var prop, value, exposed = sandbox.inject({}); + var prop, + value; + var 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; + value = exposed[prop] || prop === "sandbox" && sandbox; exposeValue(sandbox, config, prop, value); } } else { @@ -5509,7 +5972,7 @@ if (typeof sinon == "undefined") { return sinon.sandbox; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -5523,14 +5986,20 @@ if (typeof sinon == "undefined") { if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}()); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend util/core.js @@ -5544,15 +6013,15 @@ if (typeof sinon == "undefined") { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + function makeApi(sinon) { var slice = Array.prototype.slice; function test(callback) { var type = typeof callback; - if (type != "function") { + if (type !== "function") { throw new TypeError("sinon.test needs to wrap a test function, got " + type); } @@ -5564,15 +6033,14 @@ if (typeof sinon == "undefined") { var oldDone = args.length && args[args.length - 1]; var exception, result; - if (typeof oldDone == "function") { - args[args.length - 1] = function sinonDone(result) { - if (result) { + if (typeof oldDone === "function") { + args[args.length - 1] = function sinonDone(res) { + if (res) { sandbox.restore(); - throw exception; } else { sandbox.verifyAndRestore(); } - oldDone(result); + oldDone(res); }; } @@ -5582,7 +6050,7 @@ if (typeof sinon == "undefined") { exception = e; } - if (typeof oldDone != "function") { + if (typeof oldDone !== "function") { if (typeof exception !== "undefined") { sandbox.restore(); throw exception; @@ -5595,7 +6063,7 @@ if (typeof sinon == "undefined") { } if (callback.length) { - return function sinonAsyncSandboxedTest(callback) { + return function sinonAsyncSandboxedTest(done) { // eslint-disable-line no-unused-vars return sinonSandboxedTest.apply(this, arguments); }; } @@ -5615,23 +6083,23 @@ if (typeof sinon == "undefined") { return test; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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"); + var core = require("./util/core"); require("./sandbox"); - module.exports = makeApi(sinon); + module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); - } else if (sinon) { - makeApi(sinon); + } else if (sinonGlobal) { + makeApi(sinonGlobal); } -}(typeof sinon == "object" && sinon || null)); +}(typeof sinon === "object" && sinon || null)); // eslint-disable-line no-undef /** * @depend util/core.js @@ -5645,8 +6113,8 @@ if (typeof sinon == "undefined") { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon) { +(function (sinonGlobal) { + function createTest(property, setUp, tearDown) { return function () { if (setUp) { @@ -5675,21 +6143,24 @@ if (typeof sinon == "undefined") { function makeApi(sinon) { function testCase(tests, prefix) { - if (!tests || typeof tests != "object") { + 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 methods = {}; var setUp = tests.setUp; var tearDown = tests.tearDown; + var testName, + property, + method; for (testName in tests) { if (tests.hasOwnProperty(testName) && !/^(setUp|tearDown)$/.test(testName)) { property = tests[testName]; - if (typeof property == "function" && rPrefix.test(testName)) { + if (typeof property === "function" && rPrefix.test(testName)) { method = property; if (setUp || tearDown) { @@ -5710,25 +6181,31 @@ if (typeof sinon == "undefined") { return testCase; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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"); + var core = require("./util/core"); require("./test"); - module.exports = makeApi(sinon); + module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + if (isNode) { loadDependencies(require, module.exports, module); - } else if (!sinon) { return; - } else { - makeApi(sinon); } -}(typeof sinon == "object" && sinon || null)); + + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon // eslint-disable-line no-undef +)); /** * @depend times_in_words.js @@ -5744,8 +6221,8 @@ if (typeof sinon == "undefined") { * * Copyright (c) 2010-2013 Christian Johansen */ - -(function (sinon, global) { +(function (sinonGlobal, global) { + var slice = Array.prototype.slice; function makeApi(sinon) { @@ -5764,11 +6241,11 @@ if (typeof sinon == "undefined") { if (method.proxy && method.proxy.isSinonProxy) { verifyIsStub(method.proxy); } else { - if (typeof method != "function") { + if (typeof method !== "function") { assert.fail(method + " is not a function"); } - if (typeof method.getCall != "function") { + if (typeof method.getCall !== "function") { assert.fail(method + " is not stubbed"); } } @@ -5783,7 +6260,7 @@ if (typeof sinon == "undefined") { } function mirrorPropAsAssertion(name, method, message) { - if (arguments.length == 2) { + if (arguments.length === 2) { message = method; method = name; } @@ -5794,10 +6271,10 @@ if (typeof sinon == "undefined") { var args = slice.call(arguments, 1); var failed = false; - if (typeof method == "function") { + if (typeof method === "function") { failed = !method(fake); } else { - failed = typeof fake[method] == "function" ? + failed = typeof fake[method] === "function" ? !fake[method].apply(fake, args) : !fake[method]; } @@ -5824,11 +6301,12 @@ if (typeof sinon == "undefined") { throw error; }, - pass: function pass(assertion) {}, + pass: function pass() {}, callOrder: function assertCallOrder() { verifyIsStub.apply(null, arguments); - var expected = "", actual = ""; + var expected = ""; + var actual = ""; if (!sinon.calledInOrder(arguments)) { try { @@ -5855,7 +6333,7 @@ if (typeof sinon == "undefined") { callCount: function assertCallCount(method, count) { verifyIsStub(method); - if (method.callCount != count) { + if (method.callCount !== count) { var msg = "expected %n to be called " + sinon.timesInWords(count) + " but was called %c%C"; failAssertion(this, method.printf(msg)); @@ -5870,11 +6348,11 @@ if (typeof sinon == "undefined") { } var o = options || {}; - var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; - var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; + 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))) { + if (method !== "expose" && (includeFail || !/^(fail)/.test(method))) { target[exposedName(prefix, method)] = this[method]; } } @@ -5891,7 +6369,8 @@ if (typeof sinon == "undefined") { "expected value to match", " expected = " + sinon.format(expectation), " actual = " + sinon.format(actual) - ] + ]; + failAssertion(this, formatted.join("\n")); } } @@ -5905,7 +6384,10 @@ if (typeof sinon == "undefined") { 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( + "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"); @@ -5923,7 +6405,7 @@ if (typeof sinon == "undefined") { return assert; } - var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + 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) { @@ -5935,15 +6417,21 @@ if (typeof sinon == "undefined") { if (isAMD) { define(loadDependencies); - } else if (isNode) { + return; + } + + 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)); + if (sinonGlobal) { + makeApi(sinonGlobal); + } +}( + typeof sinon === "object" && sinon, // eslint-disable-line no-undef + typeof global !== "undefined" ? global : self +)); return sinon; })); diff --git a/resources/lib/sinonjs/sinon-ie-1.15.4.js b/resources/lib/sinonjs/sinon-ie-1.15.4.js deleted file mode 100644 index 9eac9580a2..0000000000 --- a/resources/lib/sinonjs/sinon-ie-1.15.4.js +++ /dev/null @@ -1,103 +0,0 @@ -/** - * 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. - */ - -/** - * Helps IE run the fake timers. By defining global functions, IE allows - * them to be overwritten at a later point. If these are not defined like - * this, overwriting them will result in anything from an exception to browser - * crash. - * - * If you don't require fake timers to work in IE, don't include this file. - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2013 Christian Johansen - */ -if (typeof window !== "undefined") { - function setTimeout() {} - function clearTimeout() {} - function setImmediate() {} - function clearImmediate() {} - function setInterval() {} - function clearInterval() {} - function Date() {} - - // Reassign the original functions. Now their writable attribute - // should be true. Hackish, I know, but it works. - setTimeout = sinon.timers.setTimeout; - clearTimeout = sinon.timers.clearTimeout; - setImmediate = sinon.timers.setImmediate; - clearImmediate = sinon.timers.clearImmediate; - setInterval = sinon.timers.setInterval; - clearInterval = sinon.timers.clearInterval; - Date = sinon.timers.Date; -} - -/** - * Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows - * them to be overwritten at a later point. If these are not defined like - * this, overwriting them will result in anything from an exception to browser - * crash. - * - * If you don't require fake XHR to work in IE, don't include this file. - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2013 Christian Johansen - */ -if (typeof window !== "undefined") { - function XMLHttpRequest() {} - - // Reassign the original function. Now its writable attribute - // should be true. Hackish, I know, but it works. - XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined; -} -/** - * Helps IE run the fake XDomainRequest. By defining global functions, IE allows - * them to be overwritten at a later point. If these are not defined like - * this, overwriting them will result in anything from an exception to browser - * crash. - * - * If you don't require fake XDR to work in IE, don't include this file. - */ -if (typeof window !== "undefined") { - function XDomainRequest() {} - - // Reassign the original function. Now its writable attribute - // should be true. Hackish, I know, but it works. - XDomainRequest = sinon.xdr.XDomainRequest || undefined; -} diff --git a/tests/qunit/QUnitTestResources.php b/tests/qunit/QUnitTestResources.php index 310268f27b..b7161b1cfa 100644 --- a/tests/qunit/QUnitTestResources.php +++ b/tests/qunit/QUnitTestResources.php @@ -8,14 +8,7 @@ return [ 'test.sinonjs' => [ 'scripts' => [ - 'resources/lib/sinonjs/sinon-1.15.4.js', - // We want tests to work in IE, but can't include this as it - // will break the placeholders in Sinon because the hack it uses - // to hijack IE globals relies on running in the global scope - // and in ResourceLoader this won't be running in the global scope. - // Including it results (among other things) in sandboxed timers - // being broken due to Date inheritance being undefined. - // 'resources/lib/sinonjs/sinon-ie-1.15.4.js', + 'resources/lib/sinonjs/sinon-1.17.3.js', ], 'targets' => [ 'desktop', 'mobile' ], ], -- 2.20.1