mirror of
https://github.com/github/codeql-action.git
synced 2026-01-05 22:20:20 +08:00
193 lines
5.4 KiB
JavaScript
193 lines
5.4 KiB
JavaScript
"use strict";
|
|
|
|
const arrayProto = require("@sinonjs/commons").prototypes.array;
|
|
const createProxy = require("./proxy");
|
|
const extend = require("./util/core/extend");
|
|
const functionName = require("@sinonjs/commons").functionName;
|
|
const getPropertyDescriptor = require("./util/core/get-property-descriptor");
|
|
const deepEqual = require("@sinonjs/samsam").deepEqual;
|
|
const isEsModule = require("./util/core/is-es-module");
|
|
const proxyCallUtil = require("./proxy-call-util");
|
|
const walkObject = require("./util/core/walk-object");
|
|
const wrapMethod = require("./util/core/wrap-method");
|
|
const valueToString = require("@sinonjs/commons").valueToString;
|
|
|
|
/* cache references to library methods so that they also can be stubbed without problems */
|
|
const forEach = arrayProto.forEach;
|
|
const pop = arrayProto.pop;
|
|
const push = arrayProto.push;
|
|
const slice = arrayProto.slice;
|
|
const filter = Array.prototype.filter;
|
|
|
|
let uuid = 0;
|
|
|
|
function matches(fake, args, strict) {
|
|
const margs = fake.matchingArguments;
|
|
if (
|
|
margs.length <= args.length &&
|
|
deepEqual(slice(args, 0, margs.length), margs)
|
|
) {
|
|
return !strict || margs.length === args.length;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Public API
|
|
const spyApi = {
|
|
withArgs: function () {
|
|
const args = slice(arguments);
|
|
const matching = pop(this.matchingFakes(args, true));
|
|
if (matching) {
|
|
return matching;
|
|
}
|
|
|
|
const original = this;
|
|
const fake = this.instantiateFake();
|
|
fake.matchingArguments = args;
|
|
fake.parent = this;
|
|
push(this.fakes, fake);
|
|
|
|
fake.withArgs = function () {
|
|
return original.withArgs.apply(original, arguments);
|
|
};
|
|
|
|
forEach(original.args, function (arg, i) {
|
|
if (!matches(fake, arg)) {
|
|
return;
|
|
}
|
|
|
|
proxyCallUtil.incrementCallCount(fake);
|
|
push(fake.thisValues, original.thisValues[i]);
|
|
push(fake.args, arg);
|
|
push(fake.returnValues, original.returnValues[i]);
|
|
push(fake.exceptions, original.exceptions[i]);
|
|
push(fake.callIds, original.callIds[i]);
|
|
});
|
|
|
|
proxyCallUtil.createCallProperties(fake);
|
|
|
|
return fake;
|
|
},
|
|
|
|
// Override proxy default implementation
|
|
matchingFakes: function (args, strict) {
|
|
return filter.call(this.fakes, function (fake) {
|
|
return matches(fake, args, strict);
|
|
});
|
|
},
|
|
};
|
|
|
|
/* eslint-disable @sinonjs/no-prototype-methods/no-prototype-methods */
|
|
const delegateToCalls = proxyCallUtil.delegateToCalls;
|
|
delegateToCalls(spyApi, "callArg", false, "callArgWith", true, function () {
|
|
throw new Error(
|
|
`${this.toString()} cannot call arg since it was not yet invoked.`,
|
|
);
|
|
});
|
|
spyApi.callArgWith = spyApi.callArg;
|
|
delegateToCalls(spyApi, "callArgOn", false, "callArgOnWith", true, function () {
|
|
throw new Error(
|
|
`${this.toString()} cannot call arg since it was not yet invoked.`,
|
|
);
|
|
});
|
|
spyApi.callArgOnWith = spyApi.callArgOn;
|
|
delegateToCalls(spyApi, "throwArg", false, "throwArg", false, function () {
|
|
throw new Error(
|
|
`${this.toString()} cannot throw arg since it was not yet invoked.`,
|
|
);
|
|
});
|
|
delegateToCalls(spyApi, "yield", false, "yield", true, function () {
|
|
throw new Error(
|
|
`${this.toString()} cannot yield since it was not yet invoked.`,
|
|
);
|
|
});
|
|
// "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
|
|
spyApi.invokeCallback = spyApi.yield;
|
|
delegateToCalls(spyApi, "yieldOn", false, "yieldOn", true, function () {
|
|
throw new Error(
|
|
`${this.toString()} cannot yield since it was not yet invoked.`,
|
|
);
|
|
});
|
|
delegateToCalls(spyApi, "yieldTo", false, "yieldTo", true, function (property) {
|
|
throw new Error(
|
|
`${this.toString()} cannot yield to '${valueToString(
|
|
property,
|
|
)}' since it was not yet invoked.`,
|
|
);
|
|
});
|
|
delegateToCalls(
|
|
spyApi,
|
|
"yieldToOn",
|
|
false,
|
|
"yieldToOn",
|
|
true,
|
|
function (property) {
|
|
throw new Error(
|
|
`${this.toString()} cannot yield to '${valueToString(
|
|
property,
|
|
)}' since it was not yet invoked.`,
|
|
);
|
|
},
|
|
);
|
|
|
|
function createSpy(func) {
|
|
let name;
|
|
let funk = func;
|
|
|
|
if (typeof funk !== "function") {
|
|
funk = function () {
|
|
return;
|
|
};
|
|
} else {
|
|
name = functionName(funk);
|
|
}
|
|
|
|
const proxy = createProxy(funk, funk);
|
|
|
|
// Inherit spy API:
|
|
extend.nonEnum(proxy, spyApi);
|
|
extend.nonEnum(proxy, {
|
|
displayName: name || "spy",
|
|
fakes: [],
|
|
instantiateFake: createSpy,
|
|
id: `spy#${uuid++}`,
|
|
});
|
|
return proxy;
|
|
}
|
|
|
|
function spy(object, property, types) {
|
|
if (isEsModule(object)) {
|
|
throw new TypeError("ES Modules cannot be spied");
|
|
}
|
|
|
|
if (!property && typeof object === "function") {
|
|
return createSpy(object);
|
|
}
|
|
|
|
if (!property && typeof object === "object") {
|
|
return walkObject(spy, object);
|
|
}
|
|
|
|
if (!object && !property) {
|
|
return createSpy(function () {
|
|
return;
|
|
});
|
|
}
|
|
|
|
if (!types) {
|
|
return wrapMethod(object, property, createSpy(object[property]));
|
|
}
|
|
|
|
const descriptor = {};
|
|
const methodDesc = getPropertyDescriptor(object, property);
|
|
|
|
forEach(types, function (type) {
|
|
descriptor[type] = createSpy(methodDesc[type]);
|
|
});
|
|
|
|
return wrapMethod(object, property, descriptor);
|
|
}
|
|
|
|
extend(spy, spyApi);
|
|
module.exports = spy;
|