mirror of https://gitee.com/bigwinds/arangodb
372 lines
11 KiB
JavaScript
372 lines
11 KiB
JavaScript
/**
|
|
* @depend ../sinon.js
|
|
* @depend spy.js
|
|
*/
|
|
/*jslint eqeqeq: false, onevar: false*/
|
|
/*global module, require, sinon*/
|
|
/**
|
|
* Stub functions
|
|
*
|
|
* @author Christian Johansen (christian@cjohansen.no)
|
|
* @license BSD
|
|
*
|
|
* Copyright (c) 2010-2013 Christian Johansen
|
|
*/
|
|
"use strict";
|
|
|
|
(function (sinon) {
|
|
var commonJSModule = typeof module == "object" && typeof require == "function";
|
|
|
|
if (!sinon && commonJSModule) {
|
|
sinon = require("../sinon");
|
|
}
|
|
|
|
if (!sinon) {
|
|
return;
|
|
}
|
|
|
|
function stub(object, property, func) {
|
|
if (!!func && typeof func != "function") {
|
|
throw new TypeError("Custom stub should be function");
|
|
}
|
|
|
|
var wrapper;
|
|
|
|
if (func) {
|
|
wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
|
|
} else {
|
|
wrapper = stub.create();
|
|
}
|
|
|
|
if (!object && !property) {
|
|
return sinon.stub.create();
|
|
}
|
|
|
|
if (!property && !!object && typeof object == "object") {
|
|
for (var prop in object) {
|
|
if (typeof object[prop] === "function") {
|
|
stub(object, prop);
|
|
}
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
return sinon.wrapMethod(object, property, wrapper);
|
|
}
|
|
|
|
function getChangingValue(stub, property) {
|
|
var index = stub.callCount - 1;
|
|
var values = stub[property];
|
|
var prop = index in values ? values[index] : values[values.length - 1];
|
|
stub[property + "Last"] = prop;
|
|
|
|
return prop;
|
|
}
|
|
|
|
function getCallback(stub, args) {
|
|
var callArgAt = getChangingValue(stub, "callArgAts");
|
|
|
|
if (callArgAt < 0) {
|
|
var callArgProp = getChangingValue(stub, "callArgProps");
|
|
|
|
for (var i = 0, l = args.length; i < l; ++i) {
|
|
if (!callArgProp && typeof args[i] == "function") {
|
|
return args[i];
|
|
}
|
|
|
|
if (callArgProp && args[i] &&
|
|
typeof args[i][callArgProp] == "function") {
|
|
return args[i][callArgProp];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
return args[callArgAt];
|
|
}
|
|
|
|
var join = Array.prototype.join;
|
|
|
|
function getCallbackError(stub, func, args) {
|
|
if (stub.callArgAtsLast < 0) {
|
|
var msg;
|
|
|
|
if (stub.callArgPropsLast) {
|
|
msg = sinon.functionName(stub) +
|
|
" expected to yield to '" + stub.callArgPropsLast +
|
|
"', but no object with such a property was passed."
|
|
} else {
|
|
msg = sinon.functionName(stub) +
|
|
" expected to yield, but no callback was passed."
|
|
}
|
|
|
|
if (args.length > 0) {
|
|
msg += " Received [" + join.call(args, ", ") + "]";
|
|
}
|
|
|
|
return msg;
|
|
}
|
|
|
|
return "argument at index " + stub.callArgAtsLast + " is not a function: " + func;
|
|
}
|
|
|
|
var nextTick = (function () {
|
|
if (typeof process === "object" && typeof process.nextTick === "function") {
|
|
return process.nextTick;
|
|
} else if (typeof setImmediate === "function") {
|
|
return setImmediate;
|
|
} else {
|
|
return function (callback) {
|
|
setTimeout(callback, 0);
|
|
};
|
|
}
|
|
})();
|
|
|
|
function callCallback(stub, args) {
|
|
if (stub.callArgAts.length > 0) {
|
|
var func = getCallback(stub, args);
|
|
|
|
if (typeof func != "function") {
|
|
throw new TypeError(getCallbackError(stub, func, args));
|
|
}
|
|
|
|
var callbackArguments = getChangingValue(stub, "callbackArguments");
|
|
var callbackContext = getChangingValue(stub, "callbackContexts");
|
|
|
|
if (stub.callbackAsync) {
|
|
nextTick(function() {
|
|
func.apply(callbackContext, callbackArguments);
|
|
});
|
|
} else {
|
|
func.apply(callbackContext, callbackArguments);
|
|
}
|
|
}
|
|
}
|
|
|
|
var uuid = 0;
|
|
|
|
sinon.extend(stub, (function () {
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
return functionStub.returnValue;
|
|
};
|
|
|
|
functionStub.id = "stub#" + uuid++;
|
|
var orig = functionStub;
|
|
functionStub = sinon.spy.create(functionStub);
|
|
functionStub.func = orig;
|
|
|
|
functionStub.callArgAts = [];
|
|
functionStub.callbackArguments = [];
|
|
functionStub.callbackContexts = [];
|
|
functionStub.callArgProps = [];
|
|
|
|
sinon.extend(functionStub, stub);
|
|
functionStub._create = sinon.stub.create;
|
|
functionStub.displayName = "stub";
|
|
functionStub.toString = sinon.functionToString;
|
|
|
|
return functionStub;
|
|
},
|
|
|
|
resetBehavior: function () {
|
|
var i;
|
|
|
|
this.callArgAts = [];
|
|
this.callbackArguments = [];
|
|
this.callbackContexts = [];
|
|
this.callArgProps = [];
|
|
|
|
delete this.returnValue;
|
|
delete this.returnArgAt;
|
|
this.returnThis = false;
|
|
|
|
if (this.fakes) {
|
|
for (i = 0; i < this.fakes.length; i++) {
|
|
this.fakes[i].resetBehavior();
|
|
}
|
|
}
|
|
},
|
|
|
|
returns: function returns(value) {
|
|
this.returnValue = value;
|
|
|
|
return this;
|
|
},
|
|
|
|
returnsArg: function returnsArg(pos) {
|
|
if (typeof pos != "number") {
|
|
throw new TypeError("argument index is not number");
|
|
}
|
|
|
|
this.returnArgAt = pos;
|
|
|
|
return this;
|
|
},
|
|
|
|
returnsThis: function returnsThis() {
|
|
this.returnThis = true;
|
|
|
|
return this;
|
|
},
|
|
|
|
"throws": throwsException,
|
|
throwsException: throwsException,
|
|
|
|
callsArg: function callsArg(pos) {
|
|
if (typeof pos != "number") {
|
|
throw new TypeError("argument index is not number");
|
|
}
|
|
|
|
this.callArgAts.push(pos);
|
|
this.callbackArguments.push([]);
|
|
this.callbackContexts.push(undefined);
|
|
this.callArgProps.push(undefined);
|
|
|
|
return this;
|
|
},
|
|
|
|
callsArgOn: function callsArgOn(pos, context) {
|
|
if (typeof pos != "number") {
|
|
throw new TypeError("argument index is not number");
|
|
}
|
|
if (typeof context != "object") {
|
|
throw new TypeError("argument context is not an object");
|
|
}
|
|
|
|
this.callArgAts.push(pos);
|
|
this.callbackArguments.push([]);
|
|
this.callbackContexts.push(context);
|
|
this.callArgProps.push(undefined);
|
|
|
|
return this;
|
|
},
|
|
|
|
callsArgWith: function callsArgWith(pos) {
|
|
if (typeof pos != "number") {
|
|
throw new TypeError("argument index is not number");
|
|
}
|
|
|
|
this.callArgAts.push(pos);
|
|
this.callbackArguments.push(slice.call(arguments, 1));
|
|
this.callbackContexts.push(undefined);
|
|
this.callArgProps.push(undefined);
|
|
|
|
return this;
|
|
},
|
|
|
|
callsArgOnWith: function callsArgWith(pos, context) {
|
|
if (typeof pos != "number") {
|
|
throw new TypeError("argument index is not number");
|
|
}
|
|
if (typeof context != "object") {
|
|
throw new TypeError("argument context is not an object");
|
|
}
|
|
|
|
this.callArgAts.push(pos);
|
|
this.callbackArguments.push(slice.call(arguments, 2));
|
|
this.callbackContexts.push(context);
|
|
this.callArgProps.push(undefined);
|
|
|
|
return this;
|
|
},
|
|
|
|
yields: function () {
|
|
this.callArgAts.push(-1);
|
|
this.callbackArguments.push(slice.call(arguments, 0));
|
|
this.callbackContexts.push(undefined);
|
|
this.callArgProps.push(undefined);
|
|
|
|
return this;
|
|
},
|
|
|
|
yieldsOn: function (context) {
|
|
if (typeof context != "object") {
|
|
throw new TypeError("argument context is not an object");
|
|
}
|
|
|
|
this.callArgAts.push(-1);
|
|
this.callbackArguments.push(slice.call(arguments, 1));
|
|
this.callbackContexts.push(context);
|
|
this.callArgProps.push(undefined);
|
|
|
|
return this;
|
|
},
|
|
|
|
yieldsTo: function (prop) {
|
|
this.callArgAts.push(-1);
|
|
this.callbackArguments.push(slice.call(arguments, 1));
|
|
this.callbackContexts.push(undefined);
|
|
this.callArgProps.push(prop);
|
|
|
|
return this;
|
|
},
|
|
|
|
yieldsToOn: function (prop, context) {
|
|
if (typeof context != "object") {
|
|
throw new TypeError("argument context is not an object");
|
|
}
|
|
|
|
this.callArgAts.push(-1);
|
|
this.callbackArguments.push(slice.call(arguments, 2));
|
|
this.callbackContexts.push(context);
|
|
this.callArgProps.push(prop);
|
|
|
|
return this;
|
|
}
|
|
};
|
|
|
|
// create asynchronous versions of callsArg* and yields* methods
|
|
for (var method in proto) {
|
|
// need to avoid creating anotherasync versions of the newly added async methods
|
|
if (proto.hasOwnProperty(method) &&
|
|
method.match(/^(callsArg|yields|thenYields$)/) &&
|
|
!method.match(/Async/)) {
|
|
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 {
|
|
sinon.stub = stub;
|
|
}
|
|
}(typeof sinon == "object" && sinon || null));
|