mirror of
https://github.com/github/codeql-action.git
synced 2025-12-31 11:40:24 +08:00
473 lines
13 KiB
JavaScript
473 lines
13 KiB
JavaScript
"use strict";
|
|
|
|
var arrayProto = require("@sinonjs/commons").prototypes.array;
|
|
var logger = require("@sinonjs/commons").deprecated;
|
|
var collectOwnMethods = require("./collect-own-methods");
|
|
var getPropertyDescriptor = require("./util/core/get-property-descriptor");
|
|
var isPropertyConfigurable = require("./util/core/is-property-configurable");
|
|
var match = require("@sinonjs/samsam").createMatcher;
|
|
var sinonAssert = require("./assert");
|
|
var sinonClock = require("./util/fake-timers");
|
|
var sinonMock = require("./mock");
|
|
var sinonSpy = require("./spy");
|
|
var sinonStub = require("./stub");
|
|
var sinonFake = require("./fake");
|
|
var valueToString = require("@sinonjs/commons").valueToString;
|
|
var fakeServer = require("nise").fakeServer;
|
|
var fakeXhr = require("nise").fakeXhr;
|
|
var usePromiseLibrary = require("./util/core/use-promise-library");
|
|
|
|
var DEFAULT_LEAK_THRESHOLD = 10000;
|
|
|
|
var filter = arrayProto.filter;
|
|
var forEach = arrayProto.forEach;
|
|
var push = arrayProto.push;
|
|
var reverse = arrayProto.reverse;
|
|
|
|
function applyOnEach(fakes, method) {
|
|
var matchingFakes = filter(fakes, function (fake) {
|
|
return typeof fake[method] === "function";
|
|
});
|
|
|
|
forEach(matchingFakes, function (fake) {
|
|
fake[method]();
|
|
});
|
|
}
|
|
|
|
function Sandbox() {
|
|
var sandbox = this;
|
|
var fakeRestorers = [];
|
|
var promiseLib;
|
|
|
|
var collection = [];
|
|
var loggedLeakWarning = false;
|
|
sandbox.leakThreshold = DEFAULT_LEAK_THRESHOLD;
|
|
|
|
function addToCollection(object) {
|
|
if (
|
|
push(collection, object) > sandbox.leakThreshold &&
|
|
!loggedLeakWarning
|
|
) {
|
|
// eslint-disable-next-line no-console
|
|
logger.printWarning(
|
|
"Potential memory leak detected; be sure to call restore() to clean up your sandbox. To suppress this warning, modify the leakThreshold property of your sandbox."
|
|
);
|
|
loggedLeakWarning = true;
|
|
}
|
|
}
|
|
|
|
sandbox.assert = sinonAssert.createAssertObject();
|
|
|
|
sandbox.serverPrototype = fakeServer;
|
|
|
|
// this is for testing only
|
|
sandbox.getFakes = function getFakes() {
|
|
return collection;
|
|
};
|
|
|
|
// this is for testing only
|
|
sandbox.getRestorers = function () {
|
|
return fakeRestorers;
|
|
};
|
|
|
|
sandbox.createStubInstance = function createStubInstance() {
|
|
var stubbed = sinonStub.createStubInstance.apply(null, arguments);
|
|
|
|
var ownMethods = collectOwnMethods(stubbed);
|
|
|
|
forEach(ownMethods, function (method) {
|
|
addToCollection(method);
|
|
});
|
|
|
|
usePromiseLibrary(promiseLib, ownMethods);
|
|
|
|
return stubbed;
|
|
};
|
|
|
|
sandbox.inject = function inject(obj) {
|
|
obj.spy = function () {
|
|
return sandbox.spy.apply(null, arguments);
|
|
};
|
|
|
|
obj.stub = function () {
|
|
return sandbox.stub.apply(null, arguments);
|
|
};
|
|
|
|
obj.mock = function () {
|
|
return sandbox.mock.apply(null, arguments);
|
|
};
|
|
|
|
obj.createStubInstance = function () {
|
|
return sandbox.createStubInstance.apply(sandbox, arguments);
|
|
};
|
|
|
|
obj.fake = function () {
|
|
return sandbox.fake.apply(null, arguments);
|
|
};
|
|
|
|
obj.replace = function () {
|
|
return sandbox.replace.apply(null, arguments);
|
|
};
|
|
|
|
obj.replaceSetter = function () {
|
|
return sandbox.replaceSetter.apply(null, arguments);
|
|
};
|
|
|
|
obj.replaceGetter = function () {
|
|
return sandbox.replaceGetter.apply(null, arguments);
|
|
};
|
|
|
|
if (sandbox.clock) {
|
|
obj.clock = sandbox.clock;
|
|
}
|
|
|
|
if (sandbox.server) {
|
|
obj.server = sandbox.server;
|
|
obj.requests = sandbox.server.requests;
|
|
}
|
|
|
|
obj.match = match;
|
|
|
|
return obj;
|
|
};
|
|
|
|
sandbox.mock = function mock() {
|
|
var m = sinonMock.apply(null, arguments);
|
|
|
|
addToCollection(m);
|
|
usePromiseLibrary(promiseLib, m);
|
|
|
|
return m;
|
|
};
|
|
|
|
sandbox.reset = function reset() {
|
|
applyOnEach(collection, "reset");
|
|
applyOnEach(collection, "resetHistory");
|
|
};
|
|
|
|
sandbox.resetBehavior = function resetBehavior() {
|
|
applyOnEach(collection, "resetBehavior");
|
|
};
|
|
|
|
sandbox.resetHistory = function resetHistory() {
|
|
function privateResetHistory(f) {
|
|
var method = f.resetHistory || f.reset;
|
|
if (method) {
|
|
method.call(f);
|
|
}
|
|
}
|
|
|
|
forEach(collection, function (fake) {
|
|
if (typeof fake === "function") {
|
|
privateResetHistory(fake);
|
|
return;
|
|
}
|
|
|
|
var methods = [];
|
|
if (fake.get) {
|
|
push(methods, fake.get);
|
|
}
|
|
|
|
if (fake.set) {
|
|
push(methods, fake.set);
|
|
}
|
|
|
|
forEach(methods, privateResetHistory);
|
|
});
|
|
};
|
|
|
|
sandbox.restore = function restore() {
|
|
if (arguments.length) {
|
|
throw new Error(
|
|
"sandbox.restore() does not take any parameters. Perhaps you meant stub.restore()"
|
|
);
|
|
}
|
|
|
|
reverse(collection);
|
|
applyOnEach(collection, "restore");
|
|
collection = [];
|
|
|
|
forEach(fakeRestorers, function (restorer) {
|
|
restorer();
|
|
});
|
|
fakeRestorers = [];
|
|
|
|
sandbox.restoreContext();
|
|
};
|
|
|
|
sandbox.restoreContext = function restoreContext() {
|
|
var injectedKeys = sandbox.injectedKeys;
|
|
var injectInto = sandbox.injectInto;
|
|
|
|
if (!injectedKeys) {
|
|
return;
|
|
}
|
|
|
|
forEach(injectedKeys, function (injectedKey) {
|
|
delete injectInto[injectedKey];
|
|
});
|
|
|
|
injectedKeys = [];
|
|
};
|
|
|
|
function getFakeRestorer(object, property) {
|
|
var descriptor = getPropertyDescriptor(object, property);
|
|
|
|
function restorer() {
|
|
if (descriptor.isOwn) {
|
|
Object.defineProperty(object, property, descriptor);
|
|
} else {
|
|
delete object[property];
|
|
}
|
|
}
|
|
restorer.object = object;
|
|
restorer.property = property;
|
|
return restorer;
|
|
}
|
|
|
|
function verifyNotReplaced(object, property) {
|
|
forEach(fakeRestorers, function (fakeRestorer) {
|
|
if (
|
|
fakeRestorer.object === object &&
|
|
fakeRestorer.property === property
|
|
) {
|
|
throw new TypeError(
|
|
`Attempted to replace ${property} which is already replaced`
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
sandbox.replace = function replace(object, property, replacement) {
|
|
var descriptor = getPropertyDescriptor(object, property);
|
|
|
|
if (typeof descriptor === "undefined") {
|
|
throw new TypeError(
|
|
`Cannot replace non-existent property ${valueToString(
|
|
property
|
|
)}`
|
|
);
|
|
}
|
|
|
|
if (typeof replacement === "undefined") {
|
|
throw new TypeError("Expected replacement argument to be defined");
|
|
}
|
|
|
|
if (typeof descriptor.get === "function") {
|
|
throw new Error("Use sandbox.replaceGetter for replacing getters");
|
|
}
|
|
|
|
if (typeof descriptor.set === "function") {
|
|
throw new Error("Use sandbox.replaceSetter for replacing setters");
|
|
}
|
|
|
|
if (typeof object[property] !== typeof replacement) {
|
|
throw new TypeError(
|
|
`Cannot replace ${typeof object[
|
|
property
|
|
]} with ${typeof replacement}`
|
|
);
|
|
}
|
|
|
|
verifyNotReplaced(object, property);
|
|
|
|
// store a function for restoring the replaced property
|
|
push(fakeRestorers, getFakeRestorer(object, property));
|
|
|
|
object[property] = replacement;
|
|
|
|
return replacement;
|
|
};
|
|
|
|
sandbox.replaceGetter = function replaceGetter(
|
|
object,
|
|
property,
|
|
replacement
|
|
) {
|
|
var descriptor = getPropertyDescriptor(object, property);
|
|
|
|
if (typeof descriptor === "undefined") {
|
|
throw new TypeError(
|
|
`Cannot replace non-existent property ${valueToString(
|
|
property
|
|
)}`
|
|
);
|
|
}
|
|
|
|
if (typeof replacement !== "function") {
|
|
throw new TypeError(
|
|
"Expected replacement argument to be a function"
|
|
);
|
|
}
|
|
|
|
if (typeof descriptor.get !== "function") {
|
|
throw new Error("`object.property` is not a getter");
|
|
}
|
|
|
|
verifyNotReplaced(object, property);
|
|
|
|
// store a function for restoring the replaced property
|
|
push(fakeRestorers, getFakeRestorer(object, property));
|
|
|
|
Object.defineProperty(object, property, {
|
|
get: replacement,
|
|
configurable: isPropertyConfigurable(object, property),
|
|
});
|
|
|
|
return replacement;
|
|
};
|
|
|
|
sandbox.replaceSetter = function replaceSetter(
|
|
object,
|
|
property,
|
|
replacement
|
|
) {
|
|
var descriptor = getPropertyDescriptor(object, property);
|
|
|
|
if (typeof descriptor === "undefined") {
|
|
throw new TypeError(
|
|
`Cannot replace non-existent property ${valueToString(
|
|
property
|
|
)}`
|
|
);
|
|
}
|
|
|
|
if (typeof replacement !== "function") {
|
|
throw new TypeError(
|
|
"Expected replacement argument to be a function"
|
|
);
|
|
}
|
|
|
|
if (typeof descriptor.set !== "function") {
|
|
throw new Error("`object.property` is not a setter");
|
|
}
|
|
|
|
verifyNotReplaced(object, property);
|
|
|
|
// store a function for restoring the replaced property
|
|
push(fakeRestorers, getFakeRestorer(object, property));
|
|
|
|
// eslint-disable-next-line accessor-pairs
|
|
Object.defineProperty(object, property, {
|
|
set: replacement,
|
|
configurable: isPropertyConfigurable(object, property),
|
|
});
|
|
|
|
return replacement;
|
|
};
|
|
|
|
function commonPostInitSetup(args, spy) {
|
|
var object = args[0];
|
|
var property = args[1];
|
|
|
|
var isSpyingOnEntireObject =
|
|
typeof property === "undefined" && typeof object === "object";
|
|
|
|
if (isSpyingOnEntireObject) {
|
|
var ownMethods = collectOwnMethods(spy);
|
|
|
|
forEach(ownMethods, function (method) {
|
|
addToCollection(method);
|
|
});
|
|
|
|
usePromiseLibrary(promiseLib, ownMethods);
|
|
} else {
|
|
addToCollection(spy);
|
|
usePromiseLibrary(promiseLib, spy);
|
|
}
|
|
|
|
return spy;
|
|
}
|
|
|
|
sandbox.spy = function spy() {
|
|
var createdSpy = sinonSpy.apply(sinonSpy, arguments);
|
|
return commonPostInitSetup(arguments, createdSpy);
|
|
};
|
|
|
|
sandbox.stub = function stub() {
|
|
var createdStub = sinonStub.apply(sinonStub, arguments);
|
|
return commonPostInitSetup(arguments, createdStub);
|
|
};
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
sandbox.fake = function fake(f) {
|
|
var s = sinonFake.apply(sinonFake, arguments);
|
|
|
|
addToCollection(s);
|
|
|
|
return s;
|
|
};
|
|
|
|
forEach(Object.keys(sinonFake), function (key) {
|
|
var fakeBehavior = sinonFake[key];
|
|
if (typeof fakeBehavior === "function") {
|
|
sandbox.fake[key] = function () {
|
|
var s = fakeBehavior.apply(fakeBehavior, arguments);
|
|
|
|
addToCollection(s);
|
|
|
|
return s;
|
|
};
|
|
}
|
|
});
|
|
|
|
sandbox.useFakeTimers = function useFakeTimers(args) {
|
|
var clock = sinonClock.useFakeTimers.call(null, args);
|
|
|
|
sandbox.clock = clock;
|
|
addToCollection(clock);
|
|
|
|
return clock;
|
|
};
|
|
|
|
sandbox.verify = function verify() {
|
|
applyOnEach(collection, "verify");
|
|
};
|
|
|
|
sandbox.verifyAndRestore = function verifyAndRestore() {
|
|
var exception;
|
|
|
|
try {
|
|
sandbox.verify();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
|
|
sandbox.restore();
|
|
|
|
if (exception) {
|
|
throw exception;
|
|
}
|
|
};
|
|
|
|
sandbox.useFakeServer = function useFakeServer() {
|
|
var proto = sandbox.serverPrototype || fakeServer;
|
|
|
|
if (!proto || !proto.create) {
|
|
return null;
|
|
}
|
|
|
|
sandbox.server = proto.create();
|
|
addToCollection(sandbox.server);
|
|
|
|
return sandbox.server;
|
|
};
|
|
|
|
sandbox.useFakeXMLHttpRequest = function useFakeXMLHttpRequest() {
|
|
var xhr = fakeXhr.useFakeXMLHttpRequest();
|
|
addToCollection(xhr);
|
|
return xhr;
|
|
};
|
|
|
|
sandbox.usingPromise = function usingPromise(promiseLibrary) {
|
|
promiseLib = promiseLibrary;
|
|
collection.promiseLibrary = promiseLibrary;
|
|
|
|
return sandbox;
|
|
};
|
|
}
|
|
|
|
Sandbox.prototype.match = match;
|
|
|
|
module.exports = Sandbox;
|