vendor/assets/javascripts/sinon.js in sinon-rails-1.3.2.1 vs vendor/assets/javascripts/sinon.js in sinon-rails-1.4.2

- old
+ new

@@ -1,13 +1,14 @@ /** - * Sinon.JS 1.3.2, 2012/03/11 + * Sinon.JS 1.4.2, 2012/07/11 * * @author Christian Johansen (christian@cjohansen.no) + * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS * * (The BSD License) * - * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no + * Copyright (c) 2010-2012, 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: * @@ -32,112 +33,264 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; var sinon = (function () { -var buster = (function (buster, setTimeout) { - function extend(target) { - if (!target) { - return; - } - - for (var i = 1, l = arguments.length, prop; i < l; ++i) { - for (prop in arguments[i]) { - target[prop] = arguments[i][prop]; - } - } - - return target; - } - +var buster = (function (setTimeout, B) { + var isNode = typeof require == "function" && typeof module == "object"; var div = typeof document != "undefined" && document.createElement("div"); + var F = function () {}; - return extend(buster, { - bind: function (obj, methOrProp) { + var buster = { + bind: function bind(obj, methOrProp) { var method = typeof methOrProp == "string" ? obj[methOrProp] : methOrProp; var args = Array.prototype.slice.call(arguments, 2); - return function () { var allArgs = args.concat(Array.prototype.slice.call(arguments)); return method.apply(obj, allArgs); }; }, - create: (function () { - function F() {} + partial: function partial(fn) { + var args = [].slice.call(arguments, 1); + return function () { + return fn.apply(this, args.concat([].slice.call(arguments))); + }; + }, - return function create(object) { - F.prototype = object; - return new F(); + create: function create(object) { + F.prototype = object; + return new F(); + }, + + extend: function extend(target) { + if (!target) { return; } + for (var i = 1, l = arguments.length, prop; i < l; ++i) { + for (prop in arguments[i]) { + target[prop] = arguments[i][prop]; + } } - }()), + return target; + }, - extend: extend, - - nextTick: function (callback) { + nextTick: function nextTick(callback) { if (typeof process != "undefined" && process.nextTick) { return process.nextTick(callback); } - setTimeout(callback, 0); }, - functionName: function (func) { + functionName: function functionName(func) { if (!func) return ""; if (func.displayName) return func.displayName; if (func.name) return func.name; - var matches = func.toString().match(/function\s+([^\(]+)/m); return matches && matches[1] || ""; }, - isNode: function (obj) { + isNode: function isNode(obj) { if (!div) return false; - try { obj.appendChild(div); obj.removeChild(div); } catch (e) { return false; } - return true; }, - isElement: function (obj) { - return obj && buster.isNode(obj) && obj.nodeType === 1; - } - }); -}(buster || {}, setTimeout)); + isElement: function isElement(obj) { + return obj && obj.nodeType === 1 && buster.isNode(obj); + }, -if (typeof module == "object" && typeof require == "function") { - module.exports = buster; - buster.eventEmitter = require("./buster-event-emitter"); + isArray: function isArray(arr) { + return Object.prototype.toString.call(arr) == "[object Array]"; + }, - Object.defineProperty(buster, "defineVersionGetter", { - get: function () { - return require("./define-version-getter"); + flatten: function flatten(arr) { + var result = [], arr = arr || []; + for (var i = 0, l = arr.length; i < l; ++i) { + result = result.concat(buster.isArray(arr[i]) ? flatten(arr[i]) : arr[i]); + } + return result; + }, + + each: function each(arr, callback) { + for (var i = 0, l = arr.length; i < l; ++i) { + callback(arr[i]); + } + }, + + map: function map(arr, callback) { + var results = []; + for (var i = 0, l = arr.length; i < l; ++i) { + results.push(callback(arr[i])); + } + return results; + }, + + parallel: function parallel(fns, callback) { + function cb(err, res) { + if (typeof callback == "function") { + callback(err, res); + callback = null; + } + } + if (fns.length == 0) { return cb(null, []); } + var remaining = fns.length, results = []; + function makeDone(num) { + return function done(err, result) { + if (err) { return cb(err); } + results[num] = result; + if (--remaining == 0) { cb(null, results); } + }; + } + for (var i = 0, l = fns.length; i < l; ++i) { + fns[i](makeDone(i)); + } + }, + + series: function series(fns, callback) { + function cb(err, res) { + if (typeof callback == "function") { + callback(err, res); + } + } + var remaining = fns.slice(); + var results = []; + function callNext() { + if (remaining.length == 0) return cb(null, results); + var promise = remaining.shift()(next); + if (promise && typeof promise.then == "function") { + promise.then(buster.partial(next, null), next); + } + } + function next(err, result) { + if (err) return cb(err); + results.push(result); + callNext(); + } + callNext(); + }, + + countdown: function countdown(num, done) { + return function () { + if (--num == 0) done(); + }; } - }); -} + }; + if (typeof process === "object" && + typeof require === "function" && typeof module === "object") { + var crypto = require("crypto"); + var path = require("path"); -if (typeof require != "undefined") { + buster.tmpFile = function (fileName) { + var hashed = crypto.createHash("sha1"); + hashed.update(fileName); + var tmpfileName = hashed.digest("hex"); + + if (process.platform == "win32") { + return path.join(process.env["TEMP"], tmpfileName); + } else { + return path.join("/tmp", tmpfileName); + } + }; + } + + if (Array.prototype.some) { + buster.some = function (arr, fn, thisp) { + return arr.some(fn, thisp); + }; + } else { + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some + buster.some = function (arr, fun, thisp) { + if (arr == null) { throw new TypeError(); } + arr = Object(arr); + var len = arr.length >>> 0; + if (typeof fun !== "function") { throw new TypeError(); } + + for (var i = 0; i < len; i++) { + if (arr.hasOwnProperty(i) && fun.call(thisp, arr[i], i, arr)) { + return true; + } + } + + return false; + }; + } + + if (Array.prototype.filter) { + buster.filter = function (arr, fn, thisp) { + return arr.filter(fn, thisp); + }; + } else { + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter + buster.filter = function (fn, thisp) { + if (this == null) { throw new TypeError(); } + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fn != "function") { throw new TypeError(); } + + var res = []; + for (var i = 0; i < len; i++) { + if (i in t) { + var val = t[i]; // in case fun mutates this + if (fn.call(thisp, val, i, t)) { res.push(val); } + } + } + + return res; + }; + } + + if (isNode) { + module.exports = buster; + buster.eventEmitter = require("./buster-event-emitter"); + Object.defineProperty(buster, "defineVersionGetter", { + get: function () { + return require("./define-version-getter"); + } + }); + } + + return buster.extend(B || {}, buster); +}(setTimeout, buster)); +if (typeof buster === "undefined") { + var buster = {}; +} + +if (typeof module === "object" && typeof require === "function") { buster = require("buster-core"); } buster.format = buster.format || {}; buster.format.excludeConstructors = ["Object", /^.$/]; buster.format.quoteStrings = true; buster.format.ascii = (function () { + + var hasOwn = Object.prototype.hasOwnProperty; + + var specialObjects = []; + if (typeof global != "undefined") { + specialObjects.push({ obj: global, value: "[object global]" }); + } + if (typeof document != "undefined") { + specialObjects.push({ obj: document, value: "[object HTMLDocument]" }); + } + if (typeof window != "undefined") { + specialObjects.push({ obj: window, value: "[object Window]" }); + } + function keys(object) { var k = Object.keys && Object.keys(object) || []; if (k.length == 0) { for (var prop in object) { - if (object.hasOwnProperty(prop)) { + if (hasOwn.call(object, prop)) { k.push(prop); } } } @@ -173,25 +326,32 @@ if (isCircular(object, processed)) { return "[Circular]"; } if (Object.prototype.toString.call(object) == "[object Array]") { - return ascii.array(object); + return ascii.array.call(this, object, processed); } if (!object) { return "" + object; } if (buster.isElement(object)) { return ascii.element(object); } - if (object.toString !== Object.prototype.toString) { + if (typeof object.toString == "function" && + object.toString !== Object.prototype.toString) { return object.toString(); } + for (var i = 0, l = specialObjects.length; i < l; i++) { + if (object === specialObjects[i].obj) { + return specialObjects[i].value; + } + } + return ascii.object.call(this, object, processed, indent); } ascii.func = function (func) { return "function " + buster.functionName(func) + "() {}"; @@ -201,11 +361,11 @@ processed = processed || []; processed.push(array); var pieces = []; for (var i = 0, l = array.length; i < l; ++i) { - pieces.push(ascii(array[i], processed)); + pieces.push(ascii.call(this, array[i], processed)); } return "[" + pieces.join(", ") + "]"; }; @@ -374,15 +534,19 @@ var owned = hasOwn.call(object, property); object[property] = method; method.displayName = property; method.restore = function () { - if(owned) { - object[property] = wrappedMethod; - } else { + // For prototype properties try to reset by delete first. + // If this fails (ex: localStorage on mobile safari) then force a reset + // via direct assignment. + if (!owned) { delete object[property]; } + if (object[property] === method) { + object[property] = wrappedMethod; + } }; method.restore.sinon = true; mirrorProperties(method, wrappedMethod); @@ -412,10 +576,13 @@ F.prototype = proto; return new F(); }, deepEqual: function deepEqual(a, b) { + if (sinon.match && sinon.match.isMatcher(a)) { + return a.test(b); + } if (typeof a != "object" || typeof b != "object") { return a === b; } if (isElement(a) || isElement(b)) { @@ -563,10 +730,18 @@ setTimeout(function () { err.message = msg + err.message; throw err; }, 0); + }, + + typeOf: function (value) { + if (value === null) { + return "null"; + } + var string = Object.prototype.toString.call(value); + return string.substring(8, string.length - 1).toLowerCase(); } }; var isNode = typeof module == "object" && typeof require == "function"; @@ -582,10 +757,11 @@ module.exports.assert = require("./sinon/assert"); module.exports.sandbox = require("./sinon/sandbox"); module.exports.test = require("./sinon/test"); module.exports.testCase = require("./sinon/test_case"); module.exports.assert = require("./sinon/assert"); + module.exports.match = require("./sinon/match"); } if (buster) { var formatter = sinon.create(buster.format); formatter.quoteStrings = false; @@ -594,11 +770,11 @@ }; } else if (isNode) { try { var util = require("util"); sinon.format = function (value) { - return typeof value == "object" ? util.inspect(value) : value; + return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value; }; } catch (e) { /* Node, but no util module - would be very old, but better safe than sorry */ } @@ -609,10 +785,252 @@ /* @depend ../sinon.js */ /*jslint eqeqeq: false, onevar: false, plusplus: false*/ /*global module, require, sinon*/ /** + * Match functions + * + * @author Maximilian Antoni (mail@maxantoni.de) + * @license BSD + * + * Copyright (c) 2012 Maximilian Antoni + */ + +(function (sinon) { + var commonJSModule = typeof module == "object" && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function assertType(value, type, name) { + var actual = sinon.typeOf(value); + if (actual !== type) { + throw new TypeError("Expected type of " + name + " to be " + + type + ", but was " + actual); + } + } + + var matcher = { + toString: function () { + return this.message; + } + }; + + function isMatcher(object) { + return matcher.isPrototypeOf(object); + } + + function matchObject(expectation, actual) { + if (actual === null || actual === undefined) { + return false; + } + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + var exp = expectation[key]; + var act = actual[key]; + if (match.isMatcher(exp)) { + if (!exp.test(act)) { + return false; + } + } else if (sinon.typeOf(exp) === "object") { + if (!matchObject(exp, act)) { + return false; + } + } else if (!sinon.deepEqual(exp, act)) { + return false; + } + } + } + return true; + } + + matcher.or = function (m2) { + if (!isMatcher(m2)) { + throw new TypeError("Matcher expected"); + } + 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 (!isMatcher(m2)) { + throw new TypeError("Matcher expected"); + } + var m1 = this; + var and = sinon.create(matcher); + and.test = function (actual) { + return m1.test(actual) && m2.test(actual); + }; + and.message = m1.message + ".and(" + m2.message + ")"; + return and; + }; + + var match = function (expectation, message) { + var m = sinon.create(matcher); + var type = sinon.typeOf(expectation); + switch (type) { + case "object": + if (typeof expectation.test === "function") { + m.test = function (actual) { + return expectation.test(actual) === true; + }; + m.message = "match(" + sinon.functionName(expectation.test) + ")"; + return m; + } + var str = []; + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + str.push(key + ": " + expectation[key]); + } + } + m.test = function (actual) { + return matchObject(expectation, actual); + }; + m.message = "match(" + str.join(", ") + ")"; + break; + case "number": + m.test = function (actual) { + return expectation == actual; + }; + break; + case "string": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return actual.indexOf(expectation) !== -1; + }; + m.message = "match(\"" + expectation + "\")"; + break; + case "regexp": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return expectation.test(actual); + }; + break; + case "function": + m.test = expectation; + if (message) { + m.message = message; + } else { + m.message = "match(" + sinon.functionName(expectation) + ")"; + } + break; + default: + m.test = function (actual) { + return sinon.deepEqual(expectation, actual); + }; + } + if (!m.message) { + m.message = "match(" + expectation + ")"; + } + return m; + }; + + match.isMatcher = isMatcher; + + match.any = match(function () { + return true; + }, "any"); + + match.defined = match(function (actual) { + return actual !== null && actual !== undefined; + }, "defined"); + + match.truthy = match(function (actual) { + return !!actual; + }, "truthy"); + + match.falsy = match(function (actual) { + return !actual; + }, "falsy"); + + match.same = function (expectation) { + return match(function (actual) { + return expectation === actual; + }, "same(" + expectation + ")"); + }; + + match.typeOf = function (type) { + assertType(type, "string", "type"); + return match(function (actual) { + return sinon.typeOf(actual) === type; + }, "typeOf(\"" + type + "\")"); + }; + + match.instanceOf = function (type) { + assertType(type, "function", "type"); + return match(function (actual) { + return actual instanceof type; + }, "instanceOf(" + sinon.functionName(type) + ")"); + }; + + function createPropertyMatcher(propertyTest, messagePrefix) { + return function (property, value) { + assertType(property, "string", "property"); + var onlyProperty = arguments.length === 1; + var message = messagePrefix + "(\"" + property + "\""; + if (!onlyProperty) { + message += ", " + value; + } + message += ")"; + return match(function (actual) { + if (actual === undefined || actual === null || + !propertyTest(actual, property)) { + return false; + } + return onlyProperty || sinon.deepEqual(value, actual[property]); + }, message); + }; + } + + match.has = createPropertyMatcher(function (actual, property) { + if (typeof actual === "object") { + return property in actual; + } + return actual[property] !== undefined; + }, "has"); + + match.hasOwn = createPropertyMatcher(function (actual, property) { + return actual.hasOwnProperty(property); + }, "hasOwn"); + + match.bool = match.typeOf("boolean"); + match.number = match.typeOf("number"); + match.string = match.typeOf("string"); + match.object = match.typeOf("object"); + match.func = match.typeOf("function"); + match.array = match.typeOf("array"); + match.regexp = match.typeOf("regexp"); + match.date = match.typeOf("date"); + + if (commonJSModule) { + module.exports = match; + } else { + sinon.match = match; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend match.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** * Spy functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * @@ -637,11 +1055,11 @@ function spy(object, property) { if (!property && typeof object == "function") { return spy.create(object); } - if (!object || !property) { + if (!object && !property) { return spy.create(function () {}); } var method = object[property]; return sinon.wrapMethod(object, property, spy.create(method)); @@ -692,10 +1110,11 @@ } function incrementCallCount() { this.called = true; this.callCount += 1; + this.notCalled = false; this.calledOnce = this.callCount == 1; this.calledTwice = this.callCount == 2; this.calledThrice = this.callCount == 3; } @@ -710,10 +1129,11 @@ // Public API var spyApi = { reset: function () { this.called = false; + this.notCalled = true; this.calledOnce = false; this.calledTwice = false; this.calledThrice = false; this.callCount = 0; this.firstCall = null; @@ -723,10 +1143,15 @@ this.args = []; this.returnValues = []; this.thisValues = []; this.exceptions = []; this.callIds = []; + if (this.fakes) { + for (var i = 0; i < this.fakes.length; i++) { + this.fakes[i].reset(); + } + } }, create: function create(func) { var name; @@ -880,15 +1305,19 @@ }; delegateToCalls(spyApi, "calledOn", true); delegateToCalls(spyApi, "alwaysCalledOn", false, "calledOn"); delegateToCalls(spyApi, "calledWith", true); + delegateToCalls(spyApi, "calledWithMatch", true); delegateToCalls(spyApi, "alwaysCalledWith", false, "calledWith"); + delegateToCalls(spyApi, "alwaysCalledWithMatch", false, "calledWithMatch"); delegateToCalls(spyApi, "calledWithExactly", true); delegateToCalls(spyApi, "alwaysCalledWithExactly", false, "calledWithExactly"); delegateToCalls(spyApi, "neverCalledWith", false, "notCalledWith", function () { return true; }); + delegateToCalls(spyApi, "neverCalledWithMatch", false, "notCalledWithMatch", + function () { return true; }); delegateToCalls(spyApi, "threw", true); delegateToCalls(spyApi, "alwaysThrew", false, "threw"); delegateToCalls(spyApi, "returned", true); delegateToCalls(spyApi, "alwaysReturned", false, "returned"); delegateToCalls(spyApi, "calledWithNew", true); @@ -935,11 +1364,17 @@ return objects.join(", "); }, "*": function (spy, args) { - return args.join(", "); + var formatted = []; + + for (var i = 0, l = args.length; i < l; ++i) { + push.call(formatted, sinon.format(args[i])); + } + + return formatted.join(", "); } }; return spyApi; }())); @@ -980,26 +1415,36 @@ } return true; }, + calledWithMatch: function calledWithMatch() { + for (var i = 0, l = arguments.length; i < l; i += 1) { + var actual = this.args[i]; + var expectation = arguments[i]; + if (!sinon.match || !sinon.match(expectation).test(actual)) { + return false; + } + } + return true; + }, + calledWithExactly: function calledWithExactly() { return arguments.length == this.args.length && this.calledWith.apply(this, arguments); }, notCalledWith: function notCalledWith() { - for (var i = 0, l = arguments.length; i < l; i += 1) { - if (!sinon.deepEqual(arguments[i], this.args[i])) { - return true; - } - } - return false; + return !this.calledWith.apply(this, arguments); }, + notCalledWithMatch: function notCalledWithMatch() { + return !this.calledWithMatch.apply(this, arguments); + }, + returned: function returned(value) { - return this.returnValue === value; + return sinon.deepEqual(value, this.returnValue); }, threw: function threw(error) { if (typeof error == "undefined" || !this.exception) { return !!this.exception; @@ -1193,51 +1638,73 @@ } return "argument at index " + stub.callArgAt + " is not a function: " + func; } + var nextTick = (function () { + if (typeof process === "object" && typeof process.nextTick === "function") { + return process.nextTick; + } else if (typeof msSetImmediate === "function") { + return msSetImmediate.bind(window); + } else if (typeof setImmediate === "function") { + return setImmediate; + } else { + return function (callback) { + setTimeout(callback, 0); + }; + } + })(); + function callCallback(stub, args) { if (typeof stub.callArgAt == "number") { var func = getCallback(stub, args); if (typeof func != "function") { throw new TypeError(getCallbackError(stub, func, args)); } - func.apply(stub.callbackContext, stub.callbackArguments); + if (stub.callbackAsync) { + nextTick(function() { + func.apply(stub.callbackContext, stub.callbackArguments); + }); + } else { + func.apply(stub.callbackContext, stub.callbackArguments); + } } } var uuid = 0; sinon.extend(stub, (function () { - var slice = Array.prototype.slice; + var slice = Array.prototype.slice, proto; function throwsException(error, message) { if (typeof error == "string") { this.exception = new Error(message || ""); this.exception.name = error; } else if (!error) { this.exception = new Error("Error"); } else { this.exception = error; } - + return this; } - return { + proto = { create: function create() { var functionStub = function () { + + callCallback(functionStub, arguments); + if (functionStub.exception) { throw functionStub.exception; } else if (typeof functionStub.returnArgAt == 'number') { return arguments[functionStub.returnArgAt]; + } else if (functionStub.returnThis) { + return this; } - - callCallback(functionStub, arguments); - return functionStub.returnValue; }; functionStub.id = "stub#" + uuid++; var orig = functionStub; @@ -1260,16 +1727,22 @@ returnsArg: function returnsArg(pos) { if (typeof pos != "number") { throw new TypeError("argument index is not number"); } - + this.returnArgAt = pos; return this; }, + returnsThis: function returnsThis() { + this.returnThis = true; + + return this; + }, + "throws": throwsException, throwsException: throwsException, callsArg: function callsArg(pos) { if (typeof pos != "number") { @@ -1361,10 +1834,25 @@ this.callbackContext = context; return this; } }; + + // create asynchronous versions of callsArg* and yields* methods + for (var method in proto) { + if (proto.hasOwnProperty(method) && method.match(/^(callsArg|yields)/)) { + proto[method + 'Async'] = (function (syncFnName) { + return function () { + this.callbackAsync = true; + return this[syncFnName].apply(this, arguments); + }; + })(method); + } + } + + return proto; + }())); if (commonJSModule) { module.exports = stub; } else { @@ -1486,32 +1974,43 @@ this.restore(); if (messages.length > 0) { sinon.expectation.fail(messages.concat(met).join("\n")); + } else { + sinon.expectation.pass(messages.concat(met).join("\n")); } return true; }, invokeMethod: function invokeMethod(method, thisValue, args) { var expectations = this.expectations && this.expectations[method]; - var length = expectations && expectations.length || 0; + var length = expectations && expectations.length || 0, i; - for (var i = 0; i < length; i += 1) { + for (i = 0; i < length; i += 1) { if (!expectations[i].met() && expectations[i].allowsCall(thisValue, args)) { return expectations[i].apply(thisValue, args); } } - var messages = []; + var messages = [], available, exhausted = 0; for (i = 0; i < length; i += 1) { + if (expectations[i].allowsCall(thisValue, args)) { + available = available || expectations[i]; + } else { + exhausted += 1; + } push.call(messages, " " + expectations[i].toString()); } + if (exhausted === 0) { + return available.apply(thisValue, args); + } + messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ proxy: method, args: args })); @@ -1658,11 +2157,11 @@ if (!("expectedArguments" in this)) { return; } - if (!args || args.length === 0) { + if (!args) { sinon.expectation.fail(this.method + " received no arguments, expected " + this.expectedArguments.join()); } if (args.length < this.expectedArguments.length) { @@ -1683,11 +2182,11 @@ } } }, allowsCall: function allowsCall(thisValue, args) { - if (this.met()) { + if (this.met() && receivedMaxCalls(this)) { return false; } if ("expectedThis" in this && this.expectedThis !== thisValue) { return false; @@ -1756,15 +2255,20 @@ }, verify: function verify() { if (!this.met()) { sinon.expectation.fail(this.toString()); + } else { + sinon.expectation.pass(this.toString()); } return true; }, + pass: function(message) { + sinon.assert.pass(message); + }, fail: function (message) { var exception = new Error(message); exception.name = "ExpectationError"; throw exception; @@ -1884,11 +2388,22 @@ object[property] = original; } }); } } + if (!property && !!object && typeof object == "object") { + var stubbedObj = sinon.stub.apply(sinon, arguments); + for (var prop in stubbedObj) { + if (typeof stubbedObj[prop] === "function") { + this.add(stubbedObj[prop]); + } + } + + return stubbedObj; + } + return this.add(sinon.stub.apply(sinon, arguments)); }, mock: function mock() { return this.add(sinon.mock.apply(sinon, arguments)); @@ -1960,11 +2475,12 @@ } this.timeouts[toId] = { id: toId, func: args[0], - callAt: this.now + delay + callAt: this.now + delay, + invokeArgs: Array.prototype.slice.call(args, 2) }; if (recurring === true) { this.timeouts[toId].interval = delay; } @@ -2094,23 +2610,30 @@ timer = { func: this.timeouts[id].func, callAt: this.timeouts[id].callAt, interval: this.timeouts[id].interval, - id: this.timeouts[id].id + id: this.timeouts[id].id, + invokeArgs: this.timeouts[id].invokeArgs }; } } } return timer || null; }, callTimer: function (timer) { + if (typeof timer.interval == "number") { + this.timeouts[timer.id].callAt += timer.interval; + } else { + delete this.timeouts[timer.id]; + } + try { if (typeof timer.func == "function") { - timer.func.call(null); + timer.func.apply(null, timer.invokeArgs); } else { eval(timer.func); } } catch (e) { var exception = e; @@ -2121,16 +2644,10 @@ throw exception; } return; } - if (typeof timer.interval == "number") { - this.timeouts[timer.id].callAt += timer.interval; - } else { - delete this.timeouts[timer.id]; - } - if (exception) { throw exception; } }, @@ -2202,15 +2719,23 @@ function restore() { var method; for (var i = 0, l = this.methods.length; i < l; i++) { method = this.methods[i]; - global[method] = this["_" + method]; + if (global[method].hadOwnProperty) { + global[method] = this["_" + method]; + } else { + delete global[method]; + } } + + // Prevent multiple executions which will completely remove these props + this.methods = []; } function stubGlobal(method, clock) { + clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method); clock["_" + method] = global[method]; if (method == "Date") { var date = mirrorDateProperties(clock[method], global[method]); global[method] = date; @@ -2847,11 +3372,11 @@ } return response; } - var wloc = window.location; + var wloc = typeof window !== "undefined" ? window.location : {}; var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); function matchOne(response, reqMethod, reqUrl) { var rmeth = response.method; var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); @@ -3531,22 +4056,26 @@ mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); + mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new"); + mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new"); mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); + mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C"); mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); + mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C"); mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); + mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); mirrorPropAsAssertion("threw", "%n did not throw exception%C"); mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); if (commonJSModule) { module.exports = assert; } else { sinon.assert = assert; } }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : global)); -return sinon;}.call(typeof window != 'undefined' && window || {})); - +return sinon;}.call(typeof window != 'undefined' && window || {})); \ No newline at end of file