Skip to content

Commit

Permalink
test_runner: add __proto__ null
Browse files Browse the repository at this point in the history
PR-URL: #48663
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
  • Loading branch information
rluvaton authored and RafaelGSS committed Aug 17, 2023
1 parent 314bd60 commit fa19b0e
Show file tree
Hide file tree
Showing 12 changed files with 183 additions and 25 deletions.
8 changes: 8 additions & 0 deletions .eslintrc.js
Expand Up @@ -111,6 +111,14 @@ module.exports = {
},
] },
},
{
files: [
'lib/internal/test_runner/**/*.js',
],
rules: {
'node-core/set-proto-to-null-in-object': 'error',
},
},
],
rules: {
// ESLint built-in rules
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/test_runner/coverage.js
Expand Up @@ -250,7 +250,7 @@ class TestCoverage {
let dir;

try {
mkdirSync(this.originalCoverageDirectory, { recursive: true });
mkdirSync(this.originalCoverageDirectory, { __proto__: null, recursive: true });
dir = opendirSync(this.coverageDirectory);

for (let entry; (entry = dir.readSync()) !== null;) {
Expand Down
3 changes: 2 additions & 1 deletion lib/internal/test_runner/harness.js
Expand Up @@ -116,6 +116,7 @@ function setup(root) {
const globalOptions = parseCommandLine();

const hook = createHook({
__proto__: null,
init(asyncId, type, triggerAsyncId, resource) {
if (resource instanceof Test) {
testResources.set(asyncId, resource);
Expand Down Expand Up @@ -216,7 +217,7 @@ function runInParentContext(Factory) {

const test = (name, options, fn) => run(name, options, fn);
ArrayPrototypeForEach(['skip', 'todo', 'only'], (keyword) => {
test[keyword] = (name, options, fn) => run(name, options, fn, { [keyword]: true });
test[keyword] = (name, options, fn) => run(name, options, fn, { __proto__: null, [keyword]: true });
});
return test;
}
Expand Down
8 changes: 6 additions & 2 deletions lib/internal/test_runner/mock/mock.js
Expand Up @@ -133,7 +133,7 @@ class MockTracker {
validateObject(options, 'options');
const { times = Infinity } = options;
validateTimes(times, 'options.times');
const ctx = new MockFunctionContext(implementation, { original }, times);
const ctx = new MockFunctionContext(implementation, { __proto__: null, original }, times);
return this.#setupMock(ctx, original);
}

Expand Down Expand Up @@ -189,7 +189,7 @@ class MockTracker {
);
}

const restore = { descriptor, object: objectOrFunction, methodName };
const restore = { __proto__: null, descriptor, object: objectOrFunction, methodName };
const impl = implementation === kDefaultFunction ?
original : implementation;
const ctx = new MockFunctionContext(impl, restore, times);
Expand Down Expand Up @@ -238,6 +238,7 @@ class MockTracker {
}

return this.method(object, methodName, implementation, {
__proto__: null,
...options,
getter,
});
Expand Down Expand Up @@ -265,6 +266,7 @@ class MockTracker {
}

return this.method(object, methodName, implementation, {
__proto__: null,
...options,
setter,
});
Expand Down Expand Up @@ -297,6 +299,7 @@ class MockTracker {
throw err;
} finally {
FunctionPrototypeCall(trackCall, ctx, {
__proto__: null,
arguments: argList,
error,
result,
Expand All @@ -321,6 +324,7 @@ class MockTracker {
throw err;
} finally {
FunctionPrototypeCall(trackCall, ctx, {
__proto__: null,
arguments: argList,
error,
result,
Expand Down
5 changes: 4 additions & 1 deletion lib/internal/test_runner/mock/mock_timers.js
Expand Up @@ -45,7 +45,7 @@ function setPosition(node, pos) {
}

function abortIt(signal) {
return new AbortError(undefined, { cause: signal.reason });
return new AbortError(undefined, { __proto__: null, cause: signal.reason });
}

const SUPPORTED_TIMERS = ['setTimeout', 'setInterval'];
Expand Down Expand Up @@ -194,7 +194,9 @@ class MockTimers {

#toggleEnableTimers(activate) {
const options = {
__proto__: null,
toFake: {
__proto__: null,
setTimeout: () => {
this.#realSetTimeout = globalThis.setTimeout;
this.#realClearTimeout = globalThis.clearTimeout;
Expand Down Expand Up @@ -233,6 +235,7 @@ class MockTimers {
},
},
toReal: {
__proto__: null,
setTimeout: () => {
globalThis.setTimeout = this.#realSetTimeout;
globalThis.clearTimeout = this.#realClearTimeout;
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/test_runner/reporter/spec.js
Expand Up @@ -42,7 +42,7 @@ class SpecReporter extends Transform {
#failedTests = [];

constructor() {
super({ writableObjectMode: true });
super({ __proto__: null, writableObjectMode: true });
}

#indent(nesting) {
Expand Down Expand Up @@ -127,7 +127,7 @@ class SpecReporter extends Transform {
}
}
_transform({ type, data }, encoding, callback) {
callback(null, this.#handleEvent({ type, data }));
callback(null, this.#handleEvent({ __proto__: null, type, data }));
}
_flush(callback) {
if (this.#failedTests.length === 0) {
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/test_runner/reporter/tap.js
Expand Up @@ -18,7 +18,7 @@ const kDefaultIndent = ' '; // 4 spaces
const kFrameStartRegExp = /^ {4}at /;
const kLineBreakRegExp = /\n|\r\n/;
const kDefaultTAPVersion = 13;
const inspectOptions = { colors: false, breakLength: Infinity };
const inspectOptions = { __proto__: null, colors: false, breakLength: Infinity };
let testModule; // Lazy loaded due to circular dependency.

function lazyLoadTest() {
Expand Down
18 changes: 9 additions & 9 deletions lib/internal/test_runner/runner.js
Expand Up @@ -135,7 +135,7 @@ function createTestFileList() {
for (let i = 0; i < testPaths.length; i++) {
const absolutePath = resolve(testPaths[i]);

processPath(absolutePath, testFiles, { userSupplied: true });
processPath(absolutePath, testFiles, { __proto__: null, userSupplied: true });
}
} catch (err) {
if (err?.code === 'ENOENT') {
Expand Down Expand Up @@ -348,9 +348,9 @@ class FileTest extends Test {
function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
const watchMode = filesWatcher != null;
const subtest = root.createSubtest(FileTest, path, async (t) => {
const args = getRunArgs({ path, inspectPort, testNamePatterns });
const args = getRunArgs({ __proto__: null, path, inspectPort, testNamePatterns });
const stdio = ['pipe', 'pipe', 'pipe'];
const env = { ...process.env, NODE_TEST_CONTEXT: 'child-v8' };
const env = { __proto__: null, ...process.env, NODE_TEST_CONTEXT: 'child-v8' };
if (watchMode) {
stdio.push('ipc');
env.WATCH_REPORT_DEPENDENCIES = '1';
Expand All @@ -359,7 +359,7 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
env.FORCE_COLOR = '1';
}

const child = spawn(process.execPath, args, { signal: t.signal, encoding: 'utf8', env, stdio });
const child = spawn(process.execPath, args, { __proto__: null, signal: t.signal, encoding: 'utf8', env, stdio });
if (watchMode) {
filesWatcher.runningProcesses.set(path, child);
filesWatcher.watcher.watchChildProcessModules(child, path);
Expand All @@ -376,7 +376,7 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
subtest.parseMessage(data);
});

const rl = createInterface({ input: child.stderr });
const rl = createInterface({ __proto__: null, input: child.stderr });
rl.on('line', (line) => {
if (isInspectorMessage(line)) {
process.stderr.write(line + '\n');
Expand All @@ -394,8 +394,8 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
});

const { 0: { 0: code, 1: signal } } = await SafePromiseAll([
once(child, 'exit', { signal: t.signal }),
finished(child.stdout, { signal: t.signal }),
once(child, 'exit', { __proto__: null, signal: t.signal }),
finished(child.stdout, { __proto__: null, signal: t.signal }),
]);

if (watchMode) {
Expand Down Expand Up @@ -428,7 +428,7 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
const runningProcesses = new SafeMap();
const runningSubtests = new SafeMap();
const watcher = new FilesWatcher({ debounce: 200, mode: 'filter', signal });
const watcher = new FilesWatcher({ __proto__: null, debounce: 200, mode: 'filter', signal });
const filesWatcher = { __proto__: null, watcher, runningProcesses, runningSubtests };

watcher.on('changed', ({ owners }) => {
Expand Down Expand Up @@ -513,7 +513,7 @@ function run(options) {
});
}

const root = createTestTree({ concurrency, timeout, signal });
const root = createTestTree({ __proto__: null, concurrency, timeout, signal });
let testFiles = files ?? createTestFileList();

if (shard) {
Expand Down
12 changes: 6 additions & 6 deletions lib/internal/test_runner/test.js
Expand Up @@ -79,7 +79,7 @@ function stopTest(timeout, signal) {
if (timeout === kDefaultTimeout) {
return once(signal, 'abort');
}
return PromisePrototypeThen(setTimeout(timeout, null, { ref: false, signal }), () => {
return PromisePrototypeThen(setTimeout(timeout, null, { __proto__: null, ref: false, signal }), () => {
throw new ERR_TEST_FAILURE(
`test timed out after ${timeout}ms`,
kTestTimeoutFailure,
Expand Down Expand Up @@ -506,7 +506,7 @@ class Test extends AsyncResource {

getRunArgs() {
const ctx = new TestContext(this);
return { ctx, args: [ctx] };
return { __proto__: null, ctx, args: [ctx] };
}

async runHook(hook, args) {
Expand Down Expand Up @@ -540,12 +540,12 @@ class Test extends AsyncResource {
const { args, ctx } = this.getRunArgs();
const after = async () => {
if (this.hooks.after.length > 0) {
await this.runHook('after', { args, ctx });
await this.runHook('after', { __proto__: null, args, ctx });
}
};
const afterEach = runOnce(async () => {
if (this.parent?.hooks.afterEach.length > 0) {
await this.parent.runHook('afterEach', { args, ctx });
await this.parent.runHook('afterEach', { __proto__: null, args, ctx });
}
});

Expand All @@ -554,7 +554,7 @@ class Test extends AsyncResource {
await this.parent.runHook('before', this.parent.getRunArgs());
}
if (this.parent?.hooks.beforeEach.length > 0) {
await this.parent.runHook('beforeEach', { args, ctx });
await this.parent.runHook('beforeEach', { __proto__: null, args, ctx });
}
const stopPromise = stopTest(this.timeout, this.signal);
const runArgs = ArrayPrototypeSlice(args);
Expand Down Expand Up @@ -811,7 +811,7 @@ class Suite extends Test {

getRunArgs() {
const ctx = new SuiteContext(this);
return { ctx, args: [ctx] };
return { __proto__: null, ctx, args: [ctx] };
}

async run() {
Expand Down
4 changes: 3 additions & 1 deletion lib/internal/test_runner/tests_stream.js
Expand Up @@ -12,7 +12,7 @@ class TestsStream extends Readable {
#canPush;

constructor() {
super({ objectMode: true });
super({ __proto__: null, objectMode: true });
this.#buffer = [];
this.#canPush = true;
}
Expand Down Expand Up @@ -83,6 +83,8 @@ class TestsStream extends Readable {

[kEmitMessage](type, data) {
this.emit(type, data);
// Disabling as this going to the user-land
// eslint-disable-next-line node-core/set-proto-to-null-in-object
this.#tryPush({ type, data });
}

Expand Down
2 changes: 1 addition & 1 deletion lib/internal/test_runner/utils.js
Expand Up @@ -81,7 +81,7 @@ function createDeferredCallback() {
resolve();
};

return { promise, cb };
return { __proto__: null, promise, cb };
}

function isTestFailureError(err) {
Expand Down

0 comments on commit fa19b0e

Please sign in to comment.