Skip to content

Commit 1519009

Browse files
committed
Merge #2703: isolate walk state from Object prototype
fixes #2702
2 parents 66df977 + f7476b5 commit 1519009

6 files changed

Lines changed: 64 additions & 6 deletions

File tree

build.cjs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env node
2-
2+
33
const fs = require("node:fs");
44
const { execFileSync } = require("node:child_process");
55
const esbuild = require("esbuild");
@@ -8,7 +8,8 @@ const pkg = require("./package.json");
88

99
// Step 1: Run Rollup to generate lib/ from src/
1010
console.log("Generating lib/ from src/ using Rollup...");
11-
execFileSync("npx", ["rollup", "-c", "rollup.config.mjs"], {
11+
const rollupCli = require.resolve("rollup/dist/bin/rollup");
12+
execFileSync(process.execPath, [rollupCli, "-c", "rollup.config.mjs"], {
1213
stdio: "inherit",
1314
});
1415

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"scripts": {
3434
"build-artifacts": "node ./build.cjs",
3535
"pretest-node": "npm run build-artifacts",
36-
"test-node": "mocha --recursive -R dot 'test/{src,issues,scripts}/**/*-test.js'",
36+
"test-node": "mocha --recursive -R dot \"test/{src,issues,scripts}/**/*-test.js\"",
3737
"pretest-headless": "npm run build-artifacts",
3838
"test-dev": "CHOKIDAR_USEPOLLING=1 npm run test-node -- --watch",
3939
"test-headless": "node ./scripts/run-browser-suite.mjs headless",
@@ -56,7 +56,7 @@
5656
"build": "npm run build-artifacts",
5757
"build-docs": "cd docs; make build",
5858
"serve-docs": "cd docs; make livereload",
59-
"lint": "eslint --max-warnings 0 '**/*.{js,cjs,mjs}'",
59+
"lint": "eslint --max-warnings 0 \"**/*.{js,cjs,mjs}\"",
6060
"pretest-webworker": "npm run build-artifacts",
6161
"prebuild": "rimraf pkg && npm run update-compatibility",
6262
"postbuild": "run-s test-esm-support test-esm-browser-build test-contract check-dependencies",

rollup.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function getAllFiles(dir, fileList = []) {
1111
if (fs.statSync(filePath).isDirectory()) {
1212
getAllFiles(filePath, fileList);
1313
} else if (filePath.endsWith(".js")) {
14-
fileList.push(filePath);
14+
fileList.push(path.normalize(filePath));
1515
}
1616
}
1717
return fileList;

src/sinon/util/core/walk.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function walkInternal(obj, iterator, context, originalObj, seen) {
6363
* @returns {void} nothing
6464
*/
6565
const walk = function (obj, iterator, context) {
66-
return walkInternal(obj, iterator, context, obj, {});
66+
return walkInternal(obj, iterator, context, obj, Object.create(null));
6767
};
6868

6969
export default walk;

test/issues/issues-test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,4 +860,29 @@ describe("issues", function () {
860860
assert(cb.calledOnce);
861861
assert.equals(cb.firstCall.args, ["Hello"]);
862862
});
863+
864+
it("#2702 - stub creation should ignore inherited non-writable Object prototype properties", function () {
865+
const descriptor = Object.getOwnPropertyDescriptor(
866+
Object.prototype,
867+
"someFlag",
868+
);
869+
870+
Object.defineProperty(Object.prototype, "someFlag", {
871+
value: "x",
872+
writable: false,
873+
configurable: true,
874+
});
875+
876+
try {
877+
refute.exception(function () {
878+
sinon.stub();
879+
});
880+
} finally {
881+
if (descriptor) {
882+
Object.defineProperty(Object.prototype, "someFlag", descriptor);
883+
} else {
884+
delete Object.prototype.someFlag;
885+
}
886+
}
887+
});
863888
});

test/src/util/core/walk-test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import referee from "@sinonjs/referee";
22
import walk from "../../../../src/sinon/util/core/walk.js";
33
import createSpy from "../../../../src/sinon/spy.js";
44
const assert = referee.assert;
5+
const refute = referee.refute;
56

67
describe("util/core/walk", function () {
78
it("should call iterator with value, key, and obj, with context as the receiver", function () {
@@ -163,4 +164,35 @@ describe("util/core/walk", function () {
163164
assert.equals(index, propertyNames.lastIndexOf(name));
164165
});
165166
});
167+
168+
it("tracks visited names without inheriting Object.prototype properties", function () {
169+
const target = {};
170+
const iterator = createSpy();
171+
const descriptor = Object.getOwnPropertyDescriptor(
172+
Object.prototype,
173+
"someFlag",
174+
);
175+
176+
// eslint-disable-next-line no-extend-native
177+
Object.defineProperty(Object.prototype, "someFlag", {
178+
value: "x",
179+
writable: false,
180+
configurable: true,
181+
});
182+
183+
try {
184+
refute.exception(function () {
185+
walk(target, iterator);
186+
});
187+
188+
assert(iterator.calledWith("someFlag", Object.prototype));
189+
} finally {
190+
if (descriptor) {
191+
// eslint-disable-next-line no-extend-native
192+
Object.defineProperty(Object.prototype, "someFlag", descriptor);
193+
} else {
194+
delete Object.prototype.someFlag;
195+
}
196+
}
197+
});
166198
});

0 commit comments

Comments
 (0)