Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

sinon

Package Overview
Dependencies
Maintainers
2
Versions
219
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sinon - npm Package Compare versions

Comparing version
1.4.2
to
1.5.0
.npmignore

Sorry, the diff of this file is not supported yet

+6
-3

@@ -5,9 +5,10 @@ Sinon.JS was written by

Contributors
August Lilleaas, augustlilleaas@gmail.com
August Lilleaas, august.lilleaas@gmail.com
Ben Hockey, neonstalwart@gmail.com
Cormac Flynn cormac.flynn@viadeoteam.com
Cormac Flynn, cormac.flynn@viadeoteam.com
Cory, seeflanigan@gmail.com
Domenic Denicola, domenic@domenicdenicola.com
Felix Geisendörfer, felix@debuggable.com
Felix Geisendörfer, felix@debuggable.com
Gavin Huang, gravof@gmail.com
Giorgos Giannoutsos, contact@nuc.gr
Glen Mailer, glen.mailer@bskyb.com

@@ -17,2 +18,3 @@ Gord Tanner, gord@tinyhippos.com

Irina Dumitrascu, me@dira.ro
Jan Kopriva, jan.kopriva@gooddata.com
Keith Cirkel, github@keithcirkel.co.uk

@@ -30,2 +32,3 @@ Kevin Turner, kevin@decipherinc.com

TEHEK Firefox, tehek@tehek.net
Tek Nynja, github@teknynja.com
Tim Ruffles, timruffles@googlemail.com

@@ -32,0 +35,0 @@ Tobias Ebnöther, ebi@gorn.ch

@@ -0,1 +1,14 @@

== 1.5.0 / 2012-10-19
* Don't force "use strict" on Sinon consumers
* Don't assume objects have hasOwnProperties. Fixes problem with e.g.
stubbing properties on process.env
* Preserve function length for spy (Maximilian Antoni)
* Add 'invokeCallback' alias for 'yield' on calls (Maximilian Antoni)
* Added matcher support for calledOn (Maximilian Antoni)
* Retain original expectation messages, for failed mocks under sinon.test
(Giorgos Giannoutsos)
* Allow yields* and callsArg* to create sequences of calls. (Domenic Denicola)
* sinon.js can catch itself in endless loop while filling stub prototype
with asynch methods (Jan Kopriva)
== 1.4.2 / 2012-07-11

@@ -2,0 +15,0 @@ * sinon.match for arrays (Maximilian Antoni)

@@ -21,2 +21,3 @@ /**

var push = [].push;
var hasOwnProperty = Object.prototype.hasOwnProperty;

@@ -97,3 +98,3 @@ if (!sinon && commonJSModule) {

if (typeof original != "function") {
if (!object.hasOwnProperty(property)) {
if (!hasOwnProperty.call(object, property)) {
throw new TypeError("Cannot stub non-existent own property " + property);

@@ -100,0 +101,0 @@ }

@@ -105,2 +105,14 @@ /**

var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
function createProxy(func) {
// Retain the function length:
if (func.length) {
return eval("(function proxy(" + vars.substring(0, func.length * 2 - 1) +
") { return proxy.invoke(func, this, slice.call(arguments)); })");
}
return function proxy() {
return proxy.invoke(func, this, slice.call(arguments));
};
}
var uuid = 0;

@@ -142,5 +154,3 @@

function proxy() {
return proxy.invoke(func, this, slice.call(arguments));
}
var proxy = createProxy(func);

@@ -371,3 +381,3 @@ sinon.extend(proxy, spy);

return {
var callApi = {
create: function create(spy, thisValue, args, returnValue, exception, id) {

@@ -387,2 +397,5 @@ var proxyCall = sinon.create(spyCall);

calledOn: function calledOn(thisValue) {
if (sinon.match && sinon.match.isMatcher(thisValue)) {
return thisValue.test(this.thisValue);
}
return this.thisValue === thisValue;

@@ -510,2 +523,4 @@ },

};
callApi.invokeCallback = callApi.yield;
return callApi;
}());

@@ -512,0 +527,0 @@

@@ -58,12 +58,24 @@ /**

function getChangingValue(stub, property) {
var index = stub.callCount - 1;
var prop = index in stub[property] ? stub[property][index] : stub[property + "Last"];
stub[property + "Last"] = prop;
return prop;
}
function getCallback(stub, args) {
if (stub.callArgAt < 0) {
var callArgAt = getChangingValue(stub, "callArgAts");
if (callArgAt < 0) {
var callArgProp = getChangingValue(stub, "callArgProps");
for (var i = 0, l = args.length; i < l; ++i) {
if (!stub.callArgProp && typeof args[i] == "function") {
if (!callArgProp && typeof args[i] == "function") {
return args[i];
}
if (stub.callArgProp && args[i] &&
typeof args[i][stub.callArgProp] == "function") {
return args[i][stub.callArgProp];
if (callArgProp && args[i] &&
typeof args[i][callArgProp] == "function") {
return args[i][callArgProp];
}

@@ -75,3 +87,3 @@ }

return args[stub.callArgAt];
return args[callArgAt];
}

@@ -82,8 +94,8 @@

function getCallbackError(stub, func, args) {
if (stub.callArgAt < 0) {
if (stub.callArgAtsLast < 0) {
var msg;
if (stub.callArgProp) {
if (stub.callArgPropsLast) {
msg = sinon.functionName(stub) +
" expected to yield to '" + stub.callArgProp +
" expected to yield to '" + stub.callArgPropsLast +
"', but no object with such a property was passed."

@@ -102,3 +114,3 @@ } else {

return "argument at index " + stub.callArgAt + " is not a function: " + func;
return "argument at index " + stub.callArgAtsLast + " is not a function: " + func;
}

@@ -121,3 +133,3 @@

function callCallback(stub, args) {
if (typeof stub.callArgAt == "number") {
if (stub.callArgAts.length > 0) {
var func = getCallback(stub, args);

@@ -129,8 +141,13 @@

var index = stub.callCount - 1;
var callbackArguments = getChangingValue(stub, "callbackArguments");
var callbackContext = getChangingValue(stub, "callbackContexts");
if (stub.callbackAsync) {
nextTick(function() {
func.apply(stub.callbackContext, stub.callbackArguments);
func.apply(callbackContext, callbackArguments);
});
} else {
func.apply(stub.callbackContext, stub.callbackArguments);
func.apply(callbackContext, callbackArguments);
}

@@ -179,2 +196,7 @@ }

functionStub.callArgAts = [];
functionStub.callbackArguments = [];
functionStub.callbackContexts = [];
functionStub.callArgProps = [];
sinon.extend(functionStub, stub);

@@ -218,4 +240,6 @@ functionStub._create = sinon.stub.create;

this.callArgAt = pos;
this.callbackArguments = [];
this.callArgAts.push(pos);
this.callbackArguments.push([]);
this.callbackContexts.push(undefined);
this.callArgProps.push(undefined);

@@ -233,5 +257,6 @@ return this;

this.callArgAt = pos;
this.callbackArguments = [];
this.callbackContext = context;
this.callArgAts.push(pos);
this.callbackArguments.push([]);
this.callbackContexts.push(context);
this.callArgProps.push(undefined);

@@ -246,4 +271,6 @@ return this;

this.callArgAt = pos;
this.callbackArguments = slice.call(arguments, 1);
this.callArgAts.push(pos);
this.callbackArguments.push(slice.call(arguments, 1));
this.callbackContexts.push(undefined);
this.callArgProps.push(undefined);

@@ -261,5 +288,6 @@ return this;

this.callArgAt = pos;
this.callbackArguments = slice.call(arguments, 2);
this.callbackContext = context;
this.callArgAts.push(pos);
this.callbackArguments.push(slice.call(arguments, 2));
this.callbackContexts.push(context);
this.callArgProps.push(undefined);

@@ -270,4 +298,6 @@ return this;

yields: function () {
this.callArgAt = -1;
this.callbackArguments = slice.call(arguments, 0);
this.callArgAts.push(-1);
this.callbackArguments.push(slice.call(arguments, 0));
this.callbackContexts.push(undefined);
this.callArgProps.push(undefined);

@@ -282,5 +312,6 @@ return this;

this.callArgAt = -1;
this.callbackArguments = slice.call(arguments, 1);
this.callbackContext = context;
this.callArgAts.push(-1);
this.callbackArguments.push(slice.call(arguments, 1));
this.callbackContexts.push(context);
this.callArgProps.push(undefined);

@@ -291,5 +322,6 @@ return this;

yieldsTo: function (prop) {
this.callArgAt = -1;
this.callArgProp = prop;
this.callbackArguments = slice.call(arguments, 1);
this.callArgAts.push(-1);
this.callbackArguments.push(slice.call(arguments, 1));
this.callbackContexts.push(undefined);
this.callArgProps.push(prop);

@@ -304,6 +336,6 @@ return this;

this.callArgAt = -1;
this.callArgProp = prop;
this.callbackArguments = slice.call(arguments, 2);
this.callbackContext = context;
this.callArgAts.push(-1);
this.callbackArguments.push(slice.call(arguments, 2));
this.callbackContexts.push(context);
this.callArgProps.push(prop);

@@ -313,6 +345,9 @@ return this;

};
// create asynchronous versions of callsArg* and yields* methods
for (var method in proto) {
if (proto.hasOwnProperty(method) && method.match(/^(callsArg|yields)/)) {
// need to avoid creating anotherasync versions of the newly added async methods
if (proto.hasOwnProperty(method) &&
method.match(/^(callsArg|yields|thenYields$)/) &&
!method.match(/Async/)) {
proto[method + 'Async'] = (function (syncFnName) {

@@ -326,5 +361,5 @@ return function () {

}
return proto;
}()));

@@ -331,0 +366,0 @@

@@ -46,3 +46,11 @@ /**

result = callback.apply(this, args);
} finally {
} catch (e) {
exception = e;
}
if (typeof exception !== "undefined") {
sandbox.restore();
throw exception;
}
else {
sandbox.verifyAndRestore();

@@ -49,0 +57,0 @@ }

/**
* @depend ../../sinon.js
* @depend event.js

@@ -3,0 +4,0 @@ */

{
"name": "sinon",
"description": "JavaScript test spies, stubs and mocks.",
"version": "1.4.2",
"version": "1.5.0",
"homepage": "http://cjohansen.no/sinon/",

@@ -6,0 +6,0 @@ "author": "Christian Johansen",

@@ -11,4 +11,4 @@ git push

sed -i "s/2012\-[0-9][0-9]\-[0-9][0-9] \-/`date +%Y`-`date +%m`-`date +%d` -/" qunit/index.html
sed -i "s/$1/$2/" index.html
sed -i "s/$1/$2/" qunit/index.html
sed -i "s/$1/$2/" docs/index.html
sed -i "s/$1/$2/g" index.html
sed -i "s/$1/$2/g" qunit/index.html
sed -i "s/$1/$2/g" docs/index.html

@@ -107,2 +107,15 @@ /*jslint onevar: false, eqeqeq: false, plusplus: false*/

assert.equals(this.collection.stub(object, "method"), object.method);
},
"on node": {
requiresSupportFor: { "process": typeof process !== "undefined" },
setUp: function () {
process.env.HELL = "Ain't too bad";
},
"stubs environment property": function () {
this.collection.stub(process.env, "HELL", "froze over");
assert.equals(process.env.HELL, "froze over");
}
}

@@ -109,0 +122,0 @@ },

@@ -25,2 +25,22 @@ /*jslint onevar: false*/

"should contain asynchronous versions of callsArg*, yields*, and thenYields methods": function() {
var stub = sinon.stub.create();
var syncVersions = 0;
var asyncVersions = 0;
for (var method in stub) {
if (stub.hasOwnProperty(method) && method.match(/^(callsArg|yields|thenYields$)/)) {
if (!method.match(/Async/)) {
syncVersions++;
} else if (method.match(/Async/)) {
asyncVersions++;
}
}
}
assert.same(syncVersions, asyncVersions,
"Stub prototype should contain same amount of synchronous and asynchronous methods");
},
"returns": {

@@ -726,3 +746,3 @@ "returns specified value": function () {

assert(spy.calledOnce);
}
},
},

@@ -1054,9 +1074,9 @@

},
"passes call to callsArgWith": function () {
var object = {};
sinon.spy(this.stub, "callsArgWith");
this.stub.callsArgWithAsync(1, object);
assert(this.stub.callsArgWith.calledWith(1, object));

@@ -1069,3 +1089,3 @@ },

this.stub.callsArgWithAsync(1, object, array);
var callback = sinon.spy(done(function () {

@@ -1088,3 +1108,3 @@ assert(callback.calledWith(object, array));

},
"passes call to callsArgOn": function () {

@@ -1101,3 +1121,3 @@ sinon.spy(this.stub, "callsArgOn");

this.stub.callsArgOnAsync(2, context);
var callback = sinon.spy(done(function () {

@@ -1108,3 +1128,3 @@ assert(callback.calledOn(context));

this.stub(1, 2, callback);
assert(!callback.called);

@@ -1119,3 +1139,3 @@ }

},
"passes call to callsArgOnWith": function () {

@@ -1134,3 +1154,3 @@ var object = {};

this.stub.callsArgOnWithAsync(1, context, object);
var callback = sinon.spy(done(function () {

@@ -1142,3 +1162,3 @@ assert(callback.calledOn(context))

this.stub(1, callback);
assert(!callback.called);

@@ -1162,3 +1182,3 @@ }

var spy = sinon.spy(done);
stub(spy);

@@ -1194,5 +1214,5 @@

}));
this.stub(spy);
assert(!spy.called);

@@ -1211,3 +1231,3 @@ }

},
"asynchronously yields to property of object argument": function (done) {

@@ -1245,3 +1265,3 @@ var stub = sinon.stub().yieldsToAsync("success");

this.stub.yieldsToOnAsync("success", context);
var callback = sinon.spy(done(function () {

@@ -1257,3 +1277,119 @@ assert(callback.calledOnce);

}
},
"yields* calls should be chainable to produce a sequence": function () {
var context = { foo: "bar" };
var obj = { method1: sinon.spy(), method2: sinon.spy() };
var obj2 = { method2: sinon.spy() };
var stub = sinon.stub().yields(1, 2)
.yieldsOn(context, 3, 4)
.yieldsTo("method1", 5, 6)
.yieldsToOn("method2", context, 7, 8);
var spy1 = sinon.spy();
var spy2 = sinon.spy();
stub(spy1);
stub(spy2);
stub(obj);
stub(obj);
stub(obj2); // should continue doing the last thing
assert(spy1.calledOnce);
assert(spy1.calledWithExactly(1, 2));
assert(spy2.calledOnce);
assert(spy2.calledAfter(spy1));
assert(spy2.calledOn(context));
assert(spy2.calledWithExactly(3, 4));
assert(obj.method1.calledOnce);
assert(obj.method1.calledAfter(spy2));
assert(obj.method1.calledWithExactly(5, 6));
assert(obj.method2.calledOnce);
assert(obj.method2.calledAfter(obj.method1));
assert(obj.method2.calledOn(context));
assert(obj.method2.calledWithExactly(7, 8));
assert(obj2.method2.calledOnce);
assert(obj2.method2.calledAfter(obj.method2));
assert(obj2.method2.calledOn(context));
assert(obj2.method2.calledWithExactly(7, 8));
},
"callsArg* calls should be chainable to produce a sequence": function () {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
var spy3 = sinon.spy();
var spy4 = sinon.spy();
var spy5 = sinon.spy();
var decoy = sinon.spy();
var context = { foo: "bar" };
var stub = sinon.stub().callsArg(0)
.callsArgWith(1, "a", "b")
.callsArgOn(2, context)
.callsArgOnWith(3, context, "c", "d");
stub(spy1);
stub(decoy, spy2);
stub(decoy, decoy, spy3);
stub(decoy, decoy, decoy, spy4);
stub(decoy, decoy, decoy, spy5); // should continue doing last thing
assert(spy1.calledOnce);
assert(spy2.calledOnce);
assert(spy2.calledAfter(spy1));
assert(spy2.calledWithExactly("a", "b"));
assert(spy3.calledOnce);
assert(spy3.calledAfter(spy2));
assert(spy3.calledOn(context));
assert(spy4.calledOnce);
assert(spy4.calledAfter(spy3));
assert(spy4.calledOn(context));
assert(spy4.calledWithExactly("c", "d"));
assert(spy5.calledOnce);
assert(spy5.calledAfter(spy4));
assert(spy5.calledOn(context));
assert(spy5.calledWithExactly("c", "d"));
assert(decoy.notCalled);
},
"yields* calls and callsArg* in combination should be chainable to produce a sequence": function () {
var stub = sinon.stub().yields(1, 2)
.callsArg(1)
.yieldsTo("method")
.callsArgWith(2, "a", "b");
var obj = { method: sinon.spy() };
var spy1 = sinon.spy();
var spy2 = sinon.spy();
var spy3 = sinon.spy();
var decoy = sinon.spy();
stub(spy1);
stub(decoy, spy2);
stub(obj);
stub(decoy, decoy, spy3);
assert(spy1.calledOnce);
assert(spy2.calledOnce);
assert(spy2.calledAfter(spy1));
assert(obj.method.calledOnce);
assert(obj.method.calledAfter(spy2));
assert(spy3.calledOnce);
assert(spy3.calledAfter(obj.method));
assert(spy3.calledWithExactly("a", "b"));
assert(decoy.notCalled);
}
});

@@ -132,9 +132,17 @@ /*jslint onevar: false, eqeqeq: false, browser: true*/

var object = { method: method };
var exception;
assert.exception(function () {
try {
sinon.test(function () {
this.mock(object).expects("method");
this.mock(object).expects("method").withExactArgs(1).once();
object.method(42);
}).call({});
}, "ExpectationError");
} catch (e) {
exception = e;
}
assert.same(exception.name, "ExpectationError");
assert.equals(exception.message,
"Unexpected call: method(42)\n" +
" Expected method(1) once (never called)");
assert.same(object.method, method);

@@ -141,0 +149,0 @@ },

pkg
node_modules

Sorry, the diff of this file is too big to display

/**
* Sinon.JS 1.4.1, 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-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:
*
* * 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.
*/
"use strict";
/*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
/**
* 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-2011 Christian Johansen
*/
function setTimeout() {}
function clearTimeout() {}
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;
setInterval = sinon.timers.setInterval;
clearInterval = sinon.timers.clearInterval;
Date = sinon.timers.Date;
/*global sinon*/
/**
* 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-2011 Christian Johansen
*/
function XMLHttpRequest() {}
// Reassign the original function. Now its writable attribute
// should be true. Hackish, I know, but it works.
XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
/**
* Sinon.JS 1.4.1, 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-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:
*
* * 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.
*/
"use strict";
/*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
/**
* 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-2011 Christian Johansen
*/
function setTimeout() {}
function clearTimeout() {}
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;
setInterval = sinon.timers.setInterval;
clearInterval = sinon.timers.clearInterval;
Date = sinon.timers.Date;
/*global sinon*/
/**
* 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-2011 Christian Johansen
*/
function XMLHttpRequest() {}
// Reassign the original function. Now its writable attribute
// should be true. Hackish, I know, but it works.
XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
/**
* Sinon.JS 1.4.1, 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-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:
*
* * 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.
*/
"use strict";
/*jslint eqeqeq: false, onevar: false*/
/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
/**
* Minimal Event interface implementation
*
* Original implementation by Sven Fuchs: https://gist.github.com/995028
* Modifications and tests by Christian Johansen.
*
* @author Sven Fuchs (svenfuchs@artweb-design.de)
* @author Christian Johansen (christian@cjohansen.no)
* @license BSD
*
* Copyright (c) 2011 Sven Fuchs, Christian Johansen
*/
if (typeof sinon == "undefined") {
this.sinon = {};
}
(function () {
var push = [].push;
sinon.Event = function Event(type, bubbles, cancelable) {
this.initEvent(type, bubbles, cancelable);
};
sinon.Event.prototype = {
initEvent: function(type, bubbles, cancelable) {
this.type = type;
this.bubbles = bubbles;
this.cancelable = cancelable;
},
stopPropagation: function () {},
preventDefault: function () {
this.defaultPrevented = true;
}
};
sinon.EventTarget = {
addEventListener: function addEventListener(event, listener, useCapture) {
this.eventListeners = this.eventListeners || {};
this.eventListeners[event] = this.eventListeners[event] || [];
push.call(this.eventListeners[event], listener);
},
removeEventListener: function removeEventListener(event, listener, useCapture) {
var listeners = this.eventListeners && this.eventListeners[event] || [];
for (var i = 0, l = listeners.length; i < l; ++i) {
if (listeners[i] == listener) {
return listeners.splice(i, 1);
}
}
},
dispatchEvent: function dispatchEvent(event) {
var type = event.type;
var listeners = this.eventListeners && this.eventListeners[type] || [];
for (var i = 0; i < listeners.length; i++) {
if (typeof listeners[i] == "function") {
listeners[i].call(this, event);
} else {
listeners[i].handleEvent(event);
}
}
return !!event.defaultPrevented;
}
};
}());
/**
* @depend event.js
*/
/*jslint eqeqeq: false, onevar: false*/
/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
/**
* Fake XMLHttpRequest object
*
* @author Christian Johansen (christian@cjohansen.no)
* @license BSD
*
* Copyright (c) 2010-2011 Christian Johansen
*/
if (typeof sinon == "undefined") {
this.sinon = {};
}
sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
// wrapper for global
(function(global) {
var xhr = sinon.xhr;
xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
xhr.GlobalActiveXObject = global.ActiveXObject;
xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
/*jsl:ignore*/
var unsafeHeaders = {
"Accept-Charset": true,
"Accept-Encoding": true,
"Connection": true,
"Content-Length": true,
"Cookie": true,
"Cookie2": true,
"Content-Transfer-Encoding": true,
"Date": true,
"Expect": true,
"Host": true,
"Keep-Alive": true,
"Referer": true,
"TE": true,
"Trailer": true,
"Transfer-Encoding": true,
"Upgrade": true,
"User-Agent": true,
"Via": true
};
/*jsl:end*/
function FakeXMLHttpRequest() {
this.readyState = FakeXMLHttpRequest.UNSENT;
this.requestHeaders = {};
this.requestBody = null;
this.status = 0;
this.statusText = "";
if (typeof FakeXMLHttpRequest.onCreate == "function") {
FakeXMLHttpRequest.onCreate(this);
}
}
function verifyState(xhr) {
if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
throw new Error("INVALID_STATE_ERR");
}
if (xhr.sendFlag) {
throw new Error("INVALID_STATE_ERR");
}
}
// filtering to enable a white-list version of Sinon FakeXhr,
// where whitelisted requests are passed through to real XHR
function each(collection, callback) {
if (!collection) return;
for (var i = 0, l = collection.length; i < l; i += 1) {
callback(collection[i]);
}
}
function some(collection, callback) {
for (var index = 0; index < collection.length; index++) {
if(callback(collection[index]) === true) return true;
};
return false;
}
// largest arity in XHR is 5 - XHR#open
var apply = function(obj,method,args) {
switch(args.length) {
case 0: return obj[method]();
case 1: return obj[method](args[0]);
case 2: return obj[method](args[0],args[1]);
case 3: return obj[method](args[0],args[1],args[2]);
case 4: return obj[method](args[0],args[1],args[2],args[3]);
case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
};
};
FakeXMLHttpRequest.filters = [];
FakeXMLHttpRequest.addFilter = function(fn) {
this.filters.push(fn)
};
var IE6Re = /MSIE 6/;
FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
var xhr = new sinon.xhr.workingXHR();
each(["open","setRequestHeader","send","abort","getResponseHeader",
"getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
function(method) {
fakeXhr[method] = function() {
return apply(xhr,method,arguments);
};
});
var copyAttrs = function(args) {
each(args, function(attr) {
try {
fakeXhr[attr] = xhr[attr]
} catch(e) {
if(!IE6Re.test(navigator.userAgent)) throw e;
}
});
};
var stateChange = function() {
fakeXhr.readyState = xhr.readyState;
if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
copyAttrs(["status","statusText"]);
}
if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
copyAttrs(["responseText"]);
}
if(xhr.readyState === FakeXMLHttpRequest.DONE) {
copyAttrs(["responseXML"]);
}
if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr);
};
if(xhr.addEventListener) {
for(var event in fakeXhr.eventListeners) {
if(fakeXhr.eventListeners.hasOwnProperty(event)) {
each(fakeXhr.eventListeners[event],function(handler) {
xhr.addEventListener(event, handler);
});
}
}
xhr.addEventListener("readystatechange",stateChange);
} else {
xhr.onreadystatechange = stateChange;
}
apply(xhr,"open",xhrArgs);
};
FakeXMLHttpRequest.useFilters = false;
function verifyRequestSent(xhr) {
if (xhr.readyState == FakeXMLHttpRequest.DONE) {
throw new Error("Request done");
}
}
function verifyHeadersReceived(xhr) {
if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
throw new Error("No headers received");
}
}
function verifyResponseBodyType(body) {
if (typeof body != "string") {
var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
body + ", which is not a string.");
error.name = "InvalidBodyException";
throw error;
}
}
sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
async: true,
open: function open(method, url, async, username, password) {
this.method = method;
this.url = url;
this.async = typeof async == "boolean" ? async : true;
this.username = username;
this.password = password;
this.responseText = null;
this.responseXML = null;
this.requestHeaders = {};
this.sendFlag = false;
if(sinon.FakeXMLHttpRequest.useFilters === true) {
var xhrArgs = arguments;
var defake = some(FakeXMLHttpRequest.filters,function(filter) {
return filter.apply(this,xhrArgs)
});
if (defake) {
return sinon.FakeXMLHttpRequest.defake(this,arguments);
}
}
this.readyStateChange(FakeXMLHttpRequest.OPENED);
},
readyStateChange: function readyStateChange(state) {
this.readyState = state;
if (typeof this.onreadystatechange == "function") {
try {
this.onreadystatechange();
} catch (e) {
sinon.logError("Fake XHR onreadystatechange handler", e);
}
}
this.dispatchEvent(new sinon.Event("readystatechange"));
},
setRequestHeader: function setRequestHeader(header, value) {
verifyState(this);
if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
throw new Error("Refused to set unsafe header \"" + header + "\"");
}
if (this.requestHeaders[header]) {
this.requestHeaders[header] += "," + value;
} else {
this.requestHeaders[header] = value;
}
},
// Helps testing
setResponseHeaders: function setResponseHeaders(headers) {
this.responseHeaders = {};
for (var header in headers) {
if (headers.hasOwnProperty(header)) {
this.responseHeaders[header] = headers[header];
}
}
if (this.async) {
this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
}
},
// Currently treats ALL data as a DOMString (i.e. no Document)
send: function send(data) {
verifyState(this);
if (!/^(get|head)$/i.test(this.method)) {
if (this.requestHeaders["Content-Type"]) {
var value = this.requestHeaders["Content-Type"].split(";");
this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
} else {
this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
}
this.requestBody = data;
}
this.errorFlag = false;
this.sendFlag = this.async;
this.readyStateChange(FakeXMLHttpRequest.OPENED);
if (typeof this.onSend == "function") {
this.onSend(this);
}
},
abort: function abort() {
this.aborted = true;
this.responseText = null;
this.errorFlag = true;
this.requestHeaders = {};
if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
this.sendFlag = false;
}
this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
},
getResponseHeader: function getResponseHeader(header) {
if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
return null;
}
if (/^Set-Cookie2?$/i.test(header)) {
return null;
}
header = header.toLowerCase();
for (var h in this.responseHeaders) {
if (h.toLowerCase() == header) {
return this.responseHeaders[h];
}
}
return null;
},
getAllResponseHeaders: function getAllResponseHeaders() {
if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
return "";
}
var headers = "";
for (var header in this.responseHeaders) {
if (this.responseHeaders.hasOwnProperty(header) &&
!/^Set-Cookie2?$/i.test(header)) {
headers += header + ": " + this.responseHeaders[header] + "\r\n";
}
}
return headers;
},
setResponseBody: function setResponseBody(body) {
verifyRequestSent(this);
verifyHeadersReceived(this);
verifyResponseBodyType(body);
var chunkSize = this.chunkSize || 10;
var index = 0;
this.responseText = "";
do {
if (this.async) {
this.readyStateChange(FakeXMLHttpRequest.LOADING);
}
this.responseText += body.substring(index, index + chunkSize);
index += chunkSize;
} while (index < body.length);
var type = this.getResponseHeader("Content-Type");
if (this.responseText &&
(!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
try {
this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
} catch (e) {
// Unable to parse XML - no biggie
}
}
if (this.async) {
this.readyStateChange(FakeXMLHttpRequest.DONE);
} else {
this.readyState = FakeXMLHttpRequest.DONE;
}
},
respond: function respond(status, headers, body) {
this.setResponseHeaders(headers || {});
this.status = typeof status == "number" ? status : 200;
this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
this.setResponseBody(body || "");
}
});
sinon.extend(FakeXMLHttpRequest, {
UNSENT: 0,
OPENED: 1,
HEADERS_RECEIVED: 2,
LOADING: 3,
DONE: 4
});
// Borrowed from JSpec
FakeXMLHttpRequest.parseXML = function parseXML(text) {
var xmlDoc;
if (typeof DOMParser != "undefined") {
var parser = new DOMParser();
xmlDoc = parser.parseFromString(text, "text/xml");
} else {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = "false";
xmlDoc.loadXML(text);
}
return xmlDoc;
};
FakeXMLHttpRequest.statusCodes = {
100: "Continue",
101: "Switching Protocols",
200: "OK",
201: "Created",
202: "Accepted",
203: "Non-Authoritative Information",
204: "No Content",
205: "Reset Content",
206: "Partial Content",
300: "Multiple Choice",
301: "Moved Permanently",
302: "Found",
303: "See Other",
304: "Not Modified",
305: "Use Proxy",
307: "Temporary Redirect",
400: "Bad Request",
401: "Unauthorized",
402: "Payment Required",
403: "Forbidden",
404: "Not Found",
405: "Method Not Allowed",
406: "Not Acceptable",
407: "Proxy Authentication Required",
408: "Request Timeout",
409: "Conflict",
410: "Gone",
411: "Length Required",
412: "Precondition Failed",
413: "Request Entity Too Large",
414: "Request-URI Too Long",
415: "Unsupported Media Type",
416: "Requested Range Not Satisfiable",
417: "Expectation Failed",
422: "Unprocessable Entity",
500: "Internal Server Error",
501: "Not Implemented",
502: "Bad Gateway",
503: "Service Unavailable",
504: "Gateway Timeout",
505: "HTTP Version Not Supported"
};
sinon.useFakeXMLHttpRequest = function () {
sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
if (xhr.supportsXHR) {
global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
}
if (xhr.supportsActiveX) {
global.ActiveXObject = xhr.GlobalActiveXObject;
}
delete sinon.FakeXMLHttpRequest.restore;
if (keepOnCreate !== true) {
delete sinon.FakeXMLHttpRequest.onCreate;
}
};
if (xhr.supportsXHR) {
global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
}
if (xhr.supportsActiveX) {
global.ActiveXObject = function ActiveXObject(objId) {
if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
return new sinon.FakeXMLHttpRequest();
}
return new xhr.GlobalActiveXObject(objId);
};
}
return sinon.FakeXMLHttpRequest;
};
sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
})(this);
if (typeof module == "object" && typeof require == "function") {
module.exports = sinon;
}
/**
* @depend fake_xml_http_request.js
*/
/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
/*global module, require, window*/
/**
* The Sinon "server" mimics a web server that receives requests from
* sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
* both synchronously and asynchronously. To respond synchronuously, canned
* answers have to be provided upfront.
*
* @author Christian Johansen (christian@cjohansen.no)
* @license BSD
*
* Copyright (c) 2010-2011 Christian Johansen
*/
if (typeof sinon == "undefined") {
var sinon = {};
}
sinon.fakeServer = (function () {
var push = [].push;
function F() {}
function create(proto) {
F.prototype = proto;
return new F();
}
function responseArray(handler) {
var response = handler;
if (Object.prototype.toString.call(handler) != "[object Array]") {
response = [200, {}, handler];
}
if (typeof response[2] != "string") {
throw new TypeError("Fake server response body should be string, but was " +
typeof response[2]);
}
return response;
}
var wloc = typeof window !== "undefined" ? window.location : {};
var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
function matchOne(response, reqMethod, reqUrl) {
var rmeth = response.method;
var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
var url = response.url;
var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
return matchMethod && matchUrl;
}
function match(response, request) {
var requestMethod = this.getHTTPMethod(request);
var requestUrl = request.url;
if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
requestUrl = requestUrl.replace(rCurrLoc, "");
}
if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
if (typeof response.response == "function") {
var ru = response.url;
var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1));
return response.response.apply(response, args);
}
return true;
}
return false;
}
return {
create: function () {
var server = create(this);
this.xhr = sinon.useFakeXMLHttpRequest();
server.requests = [];
this.xhr.onCreate = function (xhrObj) {
server.addRequest(xhrObj);
};
return server;
},
addRequest: function addRequest(xhrObj) {
var server = this;
push.call(this.requests, xhrObj);
xhrObj.onSend = function () {
server.handleRequest(this);
};
if (this.autoRespond && !this.responding) {
setTimeout(function () {
server.responding = false;
server.respond();
}, this.autoRespondAfter || 10);
this.responding = true;
}
},
getHTTPMethod: function getHTTPMethod(request) {
if (this.fakeHTTPMethods && /post/i.test(request.method)) {
var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
return !!matches ? matches[1] : request.method;
}
return request.method;
},
handleRequest: function handleRequest(xhr) {
if (xhr.async) {
if (!this.queue) {
this.queue = [];
}
push.call(this.queue, xhr);
} else {
this.processRequest(xhr);
}
},
respondWith: function respondWith(method, url, body) {
if (arguments.length == 1 && typeof method != "function") {
this.response = responseArray(method);
return;
}
if (!this.responses) { this.responses = []; }
if (arguments.length == 1) {
body = method;
url = method = null;
}
if (arguments.length == 2) {
body = url;
url = method;
method = null;
}
push.call(this.responses, {
method: method,
url: url,
response: typeof body == "function" ? body : responseArray(body)
});
},
respond: function respond() {
if (arguments.length > 0) this.respondWith.apply(this, arguments);
var queue = this.queue || [];
var request;
while(request = queue.shift()) {
this.processRequest(request);
}
},
processRequest: function processRequest(request) {
try {
if (request.aborted) {
return;
}
var response = this.response || [404, {}, ""];
if (this.responses) {
for (var i = 0, l = this.responses.length; i < l; i++) {
if (match.call(this, this.responses[i], request)) {
response = this.responses[i].response;
break;
}
}
}
if (request.readyState != 4) {
request.respond(response[0], response[1], response[2]);
}
} catch (e) {
sinon.logError("Fake server request processing", e);
}
},
restore: function restore() {
return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
}
};
}());
if (typeof module == "object" && typeof require == "function") {
module.exports = sinon;
}
/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
/*global module, require, window*/
/**
* Fake timer API
* setTimeout
* setInterval
* clearTimeout
* clearInterval
* tick
* reset
* Date
*
* Inspired by jsUnitMockTimeOut from JsUnit
*
* @author Christian Johansen (christian@cjohansen.no)
* @license BSD
*
* Copyright (c) 2010-2011 Christian Johansen
*/
if (typeof sinon == "undefined") {
var sinon = {};
}
(function (global) {
var id = 1;
function addTimer(args, recurring) {
if (args.length === 0) {
throw new Error("Function requires at least 1 parameter");
}
var toId = id++;
var delay = args[1] || 0;
if (!this.timeouts) {
this.timeouts = {};
}
this.timeouts[toId] = {
id: toId,
func: args[0],
callAt: this.now + delay,
invokeArgs: Array.prototype.slice.call(args, 2)
};
if (recurring === true) {
this.timeouts[toId].interval = delay;
}
return toId;
}
function parseTime(str) {
if (!str) {
return 0;
}
var strings = str.split(":");
var l = strings.length, i = l;
var ms = 0, parsed;
if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
throw new Error("tick only understands numbers and 'h:m:s'");
}
while (i--) {
parsed = parseInt(strings[i], 10);
if (parsed >= 60) {
throw new Error("Invalid time " + str);
}
ms += parsed * Math.pow(60, (l - i - 1));
}
return ms * 1000;
}
function createObject(object) {
var newObject;
if (Object.create) {
newObject = Object.create(object);
} else {
var F = function () {};
F.prototype = object;
newObject = new F();
}
newObject.Date.clock = newObject;
return newObject;
}
sinon.clock = {
now: 0,
create: function create(now) {
var clock = createObject(this);
if (typeof now == "number") {
clock.now = now;
}
if (!!now && typeof now == "object") {
throw new TypeError("now should be milliseconds since UNIX epoch");
}
return clock;
},
setTimeout: function setTimeout(callback, timeout) {
return addTimer.call(this, arguments, false);
},
clearTimeout: function clearTimeout(timerId) {
if (!this.timeouts) {
this.timeouts = [];
}
if (timerId in this.timeouts) {
delete this.timeouts[timerId];
}
},
setInterval: function setInterval(callback, timeout) {
return addTimer.call(this, arguments, true);
},
clearInterval: function clearInterval(timerId) {
this.clearTimeout(timerId);
},
tick: function tick(ms) {
ms = typeof ms == "number" ? ms : parseTime(ms);
var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
var timer = this.firstTimerInRange(tickFrom, tickTo);
var firstException;
while (timer && tickFrom <= tickTo) {
if (this.timeouts[timer.id]) {
tickFrom = this.now = timer.callAt;
try {
this.callTimer(timer);
} catch (e) {
firstException = firstException || e;
}
}
timer = this.firstTimerInRange(previous, tickTo);
previous = tickFrom;
}
this.now = tickTo;
if (firstException) {
throw firstException;
}
},
firstTimerInRange: function (from, to) {
var timer, smallest, originalTimer;
for (var id in this.timeouts) {
if (this.timeouts.hasOwnProperty(id)) {
if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
continue;
}
if (!smallest || this.timeouts[id].callAt < smallest) {
originalTimer = this.timeouts[id];
smallest = this.timeouts[id].callAt;
timer = {
func: this.timeouts[id].func,
callAt: this.timeouts[id].callAt,
interval: this.timeouts[id].interval,
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.apply(null, timer.invokeArgs);
} else {
eval(timer.func);
}
} catch (e) {
var exception = e;
}
if (!this.timeouts[timer.id]) {
if (exception) {
throw exception;
}
return;
}
if (exception) {
throw exception;
}
},
reset: function reset() {
this.timeouts = {};
},
Date: (function () {
var NativeDate = Date;
function ClockDate(year, month, date, hour, minute, second, ms) {
// Defensive and verbose to avoid potential harm in passing
// explicit undefined when user does not pass argument
switch (arguments.length) {
case 0:
return new NativeDate(ClockDate.clock.now);
case 1:
return new NativeDate(year);
case 2:
return new NativeDate(year, month);
case 3:
return new NativeDate(year, month, date);
case 4:
return new NativeDate(year, month, date, hour);
case 5:
return new NativeDate(year, month, date, hour, minute);
case 6:
return new NativeDate(year, month, date, hour, minute, second);
default:
return new NativeDate(year, month, date, hour, minute, second, ms);
}
}
return mirrorDateProperties(ClockDate, NativeDate);
}())
};
function mirrorDateProperties(target, source) {
if (source.now) {
target.now = function now() {
return target.clock.now;
};
} else {
delete target.now;
}
if (source.toSource) {
target.toSource = function toSource() {
return source.toSource();
};
} else {
delete target.toSource;
}
target.toString = function toString() {
return source.toString();
};
target.prototype = source.prototype;
target.parse = source.parse;
target.UTC = source.UTC;
target.prototype.toUTCString = source.prototype.toUTCString;
return target;
}
var methods = ["Date", "setTimeout", "setInterval",
"clearTimeout", "clearInterval"];
function restore() {
var method;
for (var i = 0, l = this.methods.length; i < l; i++) {
method = this.methods[i];
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;
} else {
global[method] = function () {
return clock[method].apply(clock, arguments);
};
for (var prop in clock[method]) {
if (clock[method].hasOwnProperty(prop)) {
global[method][prop] = clock[method][prop];
}
}
}
global[method].clock = clock;
}
sinon.useFakeTimers = function useFakeTimers(now) {
var clock = sinon.clock.create(now);
clock.restore = restore;
clock.methods = Array.prototype.slice.call(arguments,
typeof now == "number" ? 1 : 0);
if (clock.methods.length === 0) {
clock.methods = methods;
}
for (var i = 0, l = clock.methods.length; i < l; i++) {
stubGlobal(clock.methods[i], clock);
}
return clock;
};
}(typeof global != "undefined" && typeof global !== "function" ? global : this));
sinon.timers = {
setTimeout: setTimeout,
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval,
Date: Date
};
if (typeof module == "object" && typeof require == "function") {
module.exports = sinon;
}
/**
* @depend fake_server.js
* @depend fake_timers.js
*/
/*jslint browser: true, eqeqeq: false, onevar: false*/
/*global sinon*/
/**
* Add-on for sinon.fakeServer that automatically handles a fake timer along with
* the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
* 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
* it polls the object for completion with setInterval. Dispite the direct
* motivation, there is nothing jQuery-specific in this file, so it can be used
* in any environment where the ajax implementation depends on setInterval or
* setTimeout.
*
* @author Christian Johansen (christian@cjohansen.no)
* @license BSD
*
* Copyright (c) 2010-2011 Christian Johansen
*/
(function () {
function Server() {}
Server.prototype = sinon.fakeServer;
sinon.fakeServerWithClock = new Server();
sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
if (xhr.async) {
if (typeof setTimeout.clock == "object") {
this.clock = setTimeout.clock;
} else {
this.clock = sinon.useFakeTimers();
this.resetClock = true;
}
if (!this.longestTimeout) {
var clockSetTimeout = this.clock.setTimeout;
var clockSetInterval = this.clock.setInterval;
var server = this;
this.clock.setTimeout = function (fn, timeout) {
server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
return clockSetTimeout.apply(this, arguments);
};
this.clock.setInterval = function (fn, timeout) {
server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
return clockSetInterval.apply(this, arguments);
};
}
}
return sinon.fakeServer.addRequest.call(this, xhr);
};
sinon.fakeServerWithClock.respond = function respond() {
var returnVal = sinon.fakeServer.respond.apply(this, arguments);
if (this.clock) {
this.clock.tick(this.longestTimeout || 0);
this.longestTimeout = 0;
if (this.resetClock) {
this.clock.restore();
this.resetClock = false;
}
}
return returnVal;
};
sinon.fakeServerWithClock.restore = function restore() {
if (this.clock) {
this.clock.restore();
}
return sinon.fakeServer.restore.apply(this, arguments);
};
}());
/**
* Sinon.JS 1.4.1, 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-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:
*
* * 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.
*/
"use strict";
/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
/*global module, require, window*/
/**
* Fake timer API
* setTimeout
* setInterval
* clearTimeout
* clearInterval
* tick
* reset
* Date
*
* Inspired by jsUnitMockTimeOut from JsUnit
*
* @author Christian Johansen (christian@cjohansen.no)
* @license BSD
*
* Copyright (c) 2010-2011 Christian Johansen
*/
if (typeof sinon == "undefined") {
var sinon = {};
}
(function (global) {
var id = 1;
function addTimer(args, recurring) {
if (args.length === 0) {
throw new Error("Function requires at least 1 parameter");
}
var toId = id++;
var delay = args[1] || 0;
if (!this.timeouts) {
this.timeouts = {};
}
this.timeouts[toId] = {
id: toId,
func: args[0],
callAt: this.now + delay,
invokeArgs: Array.prototype.slice.call(args, 2)
};
if (recurring === true) {
this.timeouts[toId].interval = delay;
}
return toId;
}
function parseTime(str) {
if (!str) {
return 0;
}
var strings = str.split(":");
var l = strings.length, i = l;
var ms = 0, parsed;
if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
throw new Error("tick only understands numbers and 'h:m:s'");
}
while (i--) {
parsed = parseInt(strings[i], 10);
if (parsed >= 60) {
throw new Error("Invalid time " + str);
}
ms += parsed * Math.pow(60, (l - i - 1));
}
return ms * 1000;
}
function createObject(object) {
var newObject;
if (Object.create) {
newObject = Object.create(object);
} else {
var F = function () {};
F.prototype = object;
newObject = new F();
}
newObject.Date.clock = newObject;
return newObject;
}
sinon.clock = {
now: 0,
create: function create(now) {
var clock = createObject(this);
if (typeof now == "number") {
clock.now = now;
}
if (!!now && typeof now == "object") {
throw new TypeError("now should be milliseconds since UNIX epoch");
}
return clock;
},
setTimeout: function setTimeout(callback, timeout) {
return addTimer.call(this, arguments, false);
},
clearTimeout: function clearTimeout(timerId) {
if (!this.timeouts) {
this.timeouts = [];
}
if (timerId in this.timeouts) {
delete this.timeouts[timerId];
}
},
setInterval: function setInterval(callback, timeout) {
return addTimer.call(this, arguments, true);
},
clearInterval: function clearInterval(timerId) {
this.clearTimeout(timerId);
},
tick: function tick(ms) {
ms = typeof ms == "number" ? ms : parseTime(ms);
var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
var timer = this.firstTimerInRange(tickFrom, tickTo);
var firstException;
while (timer && tickFrom <= tickTo) {
if (this.timeouts[timer.id]) {
tickFrom = this.now = timer.callAt;
try {
this.callTimer(timer);
} catch (e) {
firstException = firstException || e;
}
}
timer = this.firstTimerInRange(previous, tickTo);
previous = tickFrom;
}
this.now = tickTo;
if (firstException) {
throw firstException;
}
},
firstTimerInRange: function (from, to) {
var timer, smallest, originalTimer;
for (var id in this.timeouts) {
if (this.timeouts.hasOwnProperty(id)) {
if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
continue;
}
if (!smallest || this.timeouts[id].callAt < smallest) {
originalTimer = this.timeouts[id];
smallest = this.timeouts[id].callAt;
timer = {
func: this.timeouts[id].func,
callAt: this.timeouts[id].callAt,
interval: this.timeouts[id].interval,
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.apply(null, timer.invokeArgs);
} else {
eval(timer.func);
}
} catch (e) {
var exception = e;
}
if (!this.timeouts[timer.id]) {
if (exception) {
throw exception;
}
return;
}
if (exception) {
throw exception;
}
},
reset: function reset() {
this.timeouts = {};
},
Date: (function () {
var NativeDate = Date;
function ClockDate(year, month, date, hour, minute, second, ms) {
// Defensive and verbose to avoid potential harm in passing
// explicit undefined when user does not pass argument
switch (arguments.length) {
case 0:
return new NativeDate(ClockDate.clock.now);
case 1:
return new NativeDate(year);
case 2:
return new NativeDate(year, month);
case 3:
return new NativeDate(year, month, date);
case 4:
return new NativeDate(year, month, date, hour);
case 5:
return new NativeDate(year, month, date, hour, minute);
case 6:
return new NativeDate(year, month, date, hour, minute, second);
default:
return new NativeDate(year, month, date, hour, minute, second, ms);
}
}
return mirrorDateProperties(ClockDate, NativeDate);
}())
};
function mirrorDateProperties(target, source) {
if (source.now) {
target.now = function now() {
return target.clock.now;
};
} else {
delete target.now;
}
if (source.toSource) {
target.toSource = function toSource() {
return source.toSource();
};
} else {
delete target.toSource;
}
target.toString = function toString() {
return source.toString();
};
target.prototype = source.prototype;
target.parse = source.parse;
target.UTC = source.UTC;
target.prototype.toUTCString = source.prototype.toUTCString;
return target;
}
var methods = ["Date", "setTimeout", "setInterval",
"clearTimeout", "clearInterval"];
function restore() {
var method;
for (var i = 0, l = this.methods.length; i < l; i++) {
method = this.methods[i];
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;
} else {
global[method] = function () {
return clock[method].apply(clock, arguments);
};
for (var prop in clock[method]) {
if (clock[method].hasOwnProperty(prop)) {
global[method][prop] = clock[method][prop];
}
}
}
global[method].clock = clock;
}
sinon.useFakeTimers = function useFakeTimers(now) {
var clock = sinon.clock.create(now);
clock.restore = restore;
clock.methods = Array.prototype.slice.call(arguments,
typeof now == "number" ? 1 : 0);
if (clock.methods.length === 0) {
clock.methods = methods;
}
for (var i = 0, l = clock.methods.length; i < l; i++) {
stubGlobal(clock.methods[i], clock);
}
return clock;
};
}(typeof global != "undefined" && typeof global !== "function" ? global : this));
sinon.timers = {
setTimeout: setTimeout,
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval,
Date: Date
};
if (typeof module == "object" && typeof require == "function") {
module.exports = sinon;
}
/**
* Sinon.JS 1.4.1, 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-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:
*
* * 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.
*/
"use strict";
/*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
/**
* 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-2011 Christian Johansen
*/
function setTimeout() {}
function clearTimeout() {}
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;
setInterval = sinon.timers.setInterval;
clearInterval = sinon.timers.clearInterval;
Date = sinon.timers.Date;

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display