test: add escapePOSIXShell util

PR-URL: https://github.com/nodejs/node/pull/55125
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
This commit is contained in:
Antoine du Hamel 2024-09-29 22:44:52 +02:00 committed by GitHub
parent 858bce5698
commit 99e0d0d218
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 273 additions and 343 deletions

View File

@ -27,11 +27,12 @@ if (common.isWindows)
const assert = require('assert');
const exec = require('child_process').exec;
let cmdline = `ulimit -c 0; ${process.execPath}`;
cmdline += ' --max-old-space-size=16 --max-semi-space-size=4';
cmdline += ' -e "a = []; for (i = 0; i < 1e9; i++) { a.push({}) }"';
const cmdline =
common.escapePOSIXShell`ulimit -c 0; "${
process.execPath
}" --max-old-space-size=16 --max-semi-space-size=4 -e "a = []; for (i = 0; i < 1e9; i++) { a.push({}) }"`;
exec(cmdline, function(err, stdout, stderr) {
exec(...cmdline, common.mustCall((err, stdout, stderr) => {
if (!err) {
console.log(stdout);
console.log(stderr);
@ -39,4 +40,4 @@ exec(cmdline, function(err, stdout, stderr) {
}
assert(common.nodeProcessAborted(err.code, err.signal));
});
}));

View File

@ -62,12 +62,14 @@ assert.ok(!arg);
let program = process.execPath;
let args = [
'--abort-on-uncaught-exception', __filename, 'test_callback_abort' ];
const options = { encoding: 'utf8' };
let options = {};
if (!common.isWindows) {
program = `ulimit -c 0 && exec ${program} ${args.join(' ')}`;
[program, options] = common.escapePOSIXShell`ulimit -c 0 && exec "${program}" ${args[0]} "${args[1]}" ${args[2]}`;
args = [];
options.shell = true;
}
options.encoding = 'utf8';
const child = spawnSync(program, args, options);
if (common.isWindows) {
assert.strictEqual(child.status, 134);

View File

@ -112,6 +112,33 @@ Creates a 10 MiB file of all null characters.
Indicates if there is more than 1gb of total memory.
### ``escapePOSIXShell`shell command` ``
Escapes values in a string template literal to pass them as env variable. On Windows, this function
does not escape anything (which is fine for most paths, as `"` is not a valid
char in a path on Windows), so for tests that must pass on Windows, you should
use it only to escape paths, inside double quotes.
This function is meant to be used for tagged template strings.
```js
const { escapePOSIXShell } = require('../common');
const fixtures = require('../common/fixtures');
const { execSync } = require('node:child_process');
const origin = fixtures.path('origin');
const destination = fixtures.path('destination');
execSync(...escapePOSIXShell`cp "${origin}" "${destination}"`);
// When you need to specify specific options, and/or additional env variables:
const [cmd, opts] = escapePOSIXShell`cp "${origin}" "${destination}"`;
console.log(typeof cmd === 'string'); // true
console.log(opts === undefined || typeof opts.env === 'object'); // true
execSync(cmd, { ...opts, stdio: 'ignore' });
execSync(cmd, { stdio: 'ignore', env: { ...opts?.env, KEY: 'value' } });
```
When possible, avoid using a shell; that way, there's no need to escape values.
### `expectsError(validator[, exact])`
* `validator` [\<Object>][<Object>] | [\<RegExp>][<RegExp>] |

View File

@ -249,15 +249,13 @@ const PIPE = (() => {
// `$node --abort-on-uncaught-exception $file child`
// the process aborts.
function childShouldThrowAndAbort() {
let testCmd = '';
const escapedArgs = escapePOSIXShell`"${process.argv[0]}" --abort-on-uncaught-exception "${process.argv[1]}" child`;
if (!isWindows) {
// Do not create core files, as it can take a lot of disk space on
// continuous testing and developers' machines
testCmd += 'ulimit -c 0 && ';
escapedArgs[0] = 'ulimit -c 0 && ' + escapedArgs[0];
}
testCmd += `"${process.argv[0]}" --abort-on-uncaught-exception `;
testCmd += `"${process.argv[1]}" child`;
const child = exec(testCmd);
const child = exec(...escapedArgs);
child.on('exit', function onExit(exitCode, signal) {
const errMsg = 'Test should have aborted ' +
`but instead exited with exit code ${exitCode}` +
@ -888,6 +886,32 @@ function spawnPromisified(...args) {
});
}
/**
* Escape values in a string template literal. On Windows, this function
* does not escape anything (which is fine for paths, as `"` is not a valid char
* in a path on Windows), so you should use it only to escape paths or other
* values on tests which are skipped on Windows.
* This function is meant to be used for tagged template strings.
* @returns {[string, object | undefined]} An array that can be passed as
* arguments to `exec` or `execSync`.
*/
function escapePOSIXShell(cmdParts, ...args) {
if (common.isWindows) {
// On Windows, paths cannot contain `"`, so we can return the string unchanged.
return [String.raw({ raw: cmdParts }, ...args)];
}
// On POSIX shells, we can pass values via the env, as there's a standard way for referencing a variable.
const env = { ...process.env };
let cmd = cmdParts[0];
for (let i = 0; i < args.length; i++) {
const envVarName = `ESCAPED_${i}`;
env[envVarName] = args[i];
cmd += '${' + envVarName + '}' + cmdParts[i + 1];
}
return [cmd, { env }];
};
function getPrintedStackTrace(stderr) {
const lines = stderr.split('\n');
@ -951,6 +975,7 @@ const common = {
childShouldThrowAndAbort,
createZeroFilledFile,
defaultAutoSelectFamilyAttemptTimeout,
escapePOSIXShell,
expectsError,
expectRequiredModule,
expectWarning,

View File

@ -11,6 +11,7 @@ const {
childShouldThrowAndAbort,
createZeroFilledFile,
enoughTestMem,
escapePOSIXShell,
expectsError,
expectWarning,
getArrayBufferViews,
@ -64,6 +65,7 @@ export {
createRequire,
createZeroFilledFile,
enoughTestMem,
escapePOSIXShell,
expectsError,
expectWarning,
getArrayBufferViews,

View File

@ -27,7 +27,8 @@ ChildProcess.prototype.spawn = function() {
};
function createChild(options, callback) {
const cmd = `"${process.execPath}" "${__filename}" child`;
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
options = { ...options, env: { ...opts?.env, ...options.env } };
return cp.exec(cmd, options, common.mustCall(callback));
}

View File

@ -13,7 +13,8 @@ if (process.argv[2] === 'child') {
const expectedStdout = `${stdoutData}\n`;
const expectedStderr = `${stderrData}\n`;
function run(options, callback) {
const cmd = `"${process.execPath}" "${__filename}" child`;
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
options = { ...options, env: { ...opts?.env, ...options.env } };
cp.exec(cmd, options, common.mustSucceed((stdout, stderr) => {
callback(stdout, stderr);

View File

@ -14,14 +14,15 @@ function runChecks(err, stdio, streamName, expected) {
// On non-Windows, we can pass the path via the env; `"` is not a valid char on
// Windows, so we can simply pass the path.
const execNode = (args, optionsOrCallback, callback) => {
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" `;
let options = optionsOrCallback;
if (typeof optionsOrCallback === 'function') {
options = undefined;
callback = optionsOrCallback;
}
return cp.exec(
`"${common.isWindows ? process.execPath : '$NODE'}" ${args}`,
common.isWindows ? options : { ...options, env: { ...process.env, NODE: process.execPath } },
cmd + args,
{ ...opts, ...options },
callback,
);
};

View File

@ -12,8 +12,7 @@ if (process.argv[2] === 'child') {
console.log(stdoutData);
console.error(stderrData);
} else {
const cmd = `"${process.execPath}" "${__filename}" child`;
const child = cp.exec(cmd, common.mustSucceed((stdout, stderr) => {
const child = cp.exec(...common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, expectedStdout);
assert.strictEqual(stderr, expectedStderr);
}));

View File

@ -18,9 +18,10 @@ if (process.argv[2] === 'child') {
return;
}
const cmd = `"${process.execPath}" "${__filename}" child`;
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
cp.exec(cmd, {
...opts,
timeout: kExpiringParentTimer,
}, common.mustCall((err, stdout, stderr) => {
console.log('[stdout]', stdout.trim());

View File

@ -18,10 +18,11 @@ if (process.argv[2] === 'child') {
return;
}
const cmd = `"${process.execPath}" "${__filename}" child`;
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
// Test with a different kill signal.
cp.exec(cmd, {
...opts,
timeout: kExpiringParentTimer,
killSignal: 'SIGKILL'
}, common.mustCall((err, stdout, stderr) => {

View File

@ -22,10 +22,11 @@ if (process.argv[2] === 'child') {
return;
}
const cmd = `"${process.execPath}" "${__filename}" child`;
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
cp.exec(cmd, {
timeout: kTimeoutNotSupposedToExpire
...opts,
timeout: kTimeoutNotSupposedToExpire,
}, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout.trim(), 'child stdout');
assert.strictEqual(stderr.trim(), 'child stderr');

View File

@ -1,5 +1,5 @@
'use strict';
require('../common');
const { escapePOSIXShell } = require('../common');
// This test checks that the maxBuffer option for child_process.spawnSync()
// works as expected.
@ -10,15 +10,12 @@ const { execSync } = require('child_process');
const msgOut = 'this is stdout';
const msgOutBuf = Buffer.from(`${msgOut}\n`);
const args = [
'-e',
`"console.log('${msgOut}')";`,
];
const [cmd, opts] = escapePOSIXShell`"${process.execPath}" -e "${`console.log('${msgOut}')`}"`;
// Verify that an error is returned if maxBuffer is surpassed.
{
assert.throws(() => {
execSync(`"${process.execPath}" ${args.join(' ')}`, { maxBuffer: 1 });
execSync(cmd, { ...opts, maxBuffer: 1 });
}, (e) => {
assert.ok(e, 'maxBuffer should error');
assert.strictEqual(e.code, 'ENOBUFS');
@ -33,8 +30,8 @@ const args = [
// Verify that a maxBuffer size of Infinity works.
{
const ret = execSync(
`"${process.execPath}" ${args.join(' ')}`,
{ maxBuffer: Infinity }
cmd,
{ ...opts, maxBuffer: Infinity },
);
assert.deepStrictEqual(ret, msgOutBuf);
@ -43,9 +40,7 @@ const args = [
// Default maxBuffer size is 1024 * 1024.
{
assert.throws(() => {
execSync(
`"${process.execPath}" -e "console.log('a'.repeat(1024 * 1024))"`
);
execSync(...escapePOSIXShell`"${process.execPath}" -e "console.log('a'.repeat(1024 * 1024))"`);
}, (e) => {
assert.ok(e, 'maxBuffer should error');
assert.strictEqual(e.code, 'ENOBUFS');
@ -56,9 +51,7 @@ const args = [
// Default maxBuffer size is 1024 * 1024.
{
const ret = execSync(
`"${process.execPath}" -e "console.log('a'.repeat(1024 * 1024 - 1))"`
);
const ret = execSync(...escapePOSIXShell`"${process.execPath}" -e "console.log('a'.repeat(1024 * 1024 - 1))"`);
assert.deepStrictEqual(
ret.toString().trim(),

View File

@ -7,16 +7,8 @@ const { promisify } = require('util');
const exec = promisify(child_process.exec);
const execFile = promisify(child_process.execFile);
// The execPath might contain chars that should be escaped in a shell context.
// On non-Windows, we can pass the path via the env; `"` is not a valid char on
// Windows, so we can simply pass the path.
const execNode = (args) => exec(
`"${common.isWindows ? process.execPath : '$NODE'}" ${args}`,
common.isWindows ? undefined : { env: { ...process.env, NODE: process.execPath } },
);
{
const promise = execNode('-p 42');
const promise = exec(...common.escapePOSIXShell`"${process.execPath}" -p 42`);
assert(promise.child instanceof child_process.ChildProcess);
promise.then(common.mustCall((obj) => {
@ -53,7 +45,7 @@ const execNode = (args) => exec(
const failingCodeWithStdoutErr =
'console.log(42);console.error(43);process.exit(1)';
{
execNode(`-e "${failingCodeWithStdoutErr}"`)
exec(...common.escapePOSIXShell`"${process.execPath}" -e "${failingCodeWithStdoutErr}"`)
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 1);
assert.strictEqual(err.stdout, '42\n');

View File

@ -32,7 +32,6 @@ const assert = require('assert');
const child = require('child_process');
const path = require('path');
const fixtures = require('../common/fixtures');
const nodejs = `"${process.execPath}"`;
if (process.argv.length > 2) {
console.log(process.argv.slice(2).join(' '));
@ -40,13 +39,13 @@ if (process.argv.length > 2) {
}
// Assert that nothing is written to stdout.
child.exec(`${nodejs} --eval 42`, common.mustSucceed((stdout, stderr) => {
child.exec(...common.escapePOSIXShell`"${process.execPath}" --eval 42`, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, '');
assert.strictEqual(stderr, '');
}));
// Assert that "42\n" is written to stderr.
child.exec(`${nodejs} --eval "console.error(42)"`,
child.exec(...common.escapePOSIXShell`"${process.execPath}" --eval "console.error(42)"`,
common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, '');
assert.strictEqual(stderr, '42\n');
@ -54,14 +53,14 @@ child.exec(`${nodejs} --eval "console.error(42)"`,
// Assert that the expected output is written to stdout.
['--print', '-p -e', '-pe', '-p'].forEach((s) => {
const cmd = `${nodejs} ${s} `;
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" ${s}`;
child.exec(`${cmd}42`, common.mustSucceed((stdout, stderr) => {
child.exec(`${cmd} 42`, opts, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, '42\n');
assert.strictEqual(stderr, '');
}));
child.exec(`${cmd} '[]'`, common.mustSucceed((stdout, stderr) => {
child.exec(`${cmd} '[]'`, opts, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, '[]\n');
assert.strictEqual(stderr, '');
}));
@ -69,29 +68,26 @@ child.exec(`${nodejs} --eval "console.error(42)"`,
// Assert that module loading works.
{
// Replace \ by / because Windows uses backslashes in paths, but they're still
// interpreted as the escape character when put between quotes.
const filename = __filename.replace(/\\/g, '/');
child.exec(`${nodejs} --eval "require('${filename}')"`,
common.mustCall((err, stdout, stderr) => {
assert.strictEqual(err.code, 42);
common.spawnPromisified(process.execPath, ['--eval', `require(${JSON.stringify(__filename)})`])
.then(common.mustCall(({ stdout, stderr, code }) => {
assert.strictEqual(stderr, '');
assert.strictEqual(
stdout, 'Loaded as a module, exiting with status code 42.\n');
assert.strictEqual(stderr, '');
assert.strictEqual(code, 42);
}));
}
// Check that builtin modules are pre-defined.
child.exec(`${nodejs} --print "os.platform()"`,
child.exec(...common.escapePOSIXShell`"${process.execPath}" --print "os.platform()"`,
common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stderr, '');
assert.strictEqual(stdout.trim(), require('os').platform());
}));
// Module path resolve bug regression test.
child.exec(`${nodejs} --eval "require('./test/parallel/test-cli-eval.js')"`,
{ cwd: path.resolve(__dirname, '../../') },
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" --eval "require('./test/parallel/test-cli-eval.js')"`;
child.exec(cmd,
{ ...opts, cwd: path.resolve(__dirname, '../../') },
common.mustCall((err, stdout, stderr) => {
assert.strictEqual(err.code, 42);
assert.strictEqual(
@ -100,7 +96,7 @@ child.exec(`${nodejs} --eval "require('./test/parallel/test-cli-eval.js')"`,
}));
// Missing argument should not crash.
child.exec(`${nodejs} -e`, common.mustCall((err, stdout, stderr) => {
child.exec(...common.escapePOSIXShell`"${process.execPath}" -e`, common.mustCall((err, stdout, stderr) => {
assert.strictEqual(err.code, 9);
assert.strictEqual(stdout, '');
assert.strictEqual(stderr.trim(),
@ -108,18 +104,18 @@ child.exec(`${nodejs} -e`, common.mustCall((err, stdout, stderr) => {
}));
// Empty program should do nothing.
child.exec(`${nodejs} -e ""`, common.mustSucceed((stdout, stderr) => {
child.exec(...common.escapePOSIXShell`"${process.execPath}" -e ""`, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, '');
assert.strictEqual(stderr, '');
}));
// "\\-42" should be interpreted as an escaped expression, not a switch.
child.exec(`${nodejs} -p "\\-42"`, common.mustSucceed((stdout, stderr) => {
child.exec(...common.escapePOSIXShell`"${process.execPath}" -p "\\-42"`, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, '-42\n');
assert.strictEqual(stderr, '');
}));
child.exec(`${nodejs} --use-strict -p process.execArgv`,
child.exec(...common.escapePOSIXShell`"${process.execPath}" --use-strict -p process.execArgv`,
common.mustSucceed((stdout, stderr) => {
assert.strictEqual(
stdout, "[ '--use-strict', '-p', 'process.execArgv' ]\n"
@ -129,25 +125,25 @@ child.exec(`${nodejs} --use-strict -p process.execArgv`,
// Regression test for https://github.com/nodejs/node/issues/3574.
{
let emptyFile = fixtures.path('empty.js');
if (common.isWindows) {
emptyFile = emptyFile.replace(/\\/g, '\\\\');
}
const emptyFile = fixtures.path('empty.js');
child.exec(`${nodejs} -e 'require("child_process").fork("${emptyFile}")'`,
common.mustSucceed((stdout, stderr) => {
common.spawnPromisified(process.execPath, ['-e', `require("child_process").fork(${JSON.stringify(emptyFile)})`])
.then(common.mustCall(({ stdout, stderr, code }) => {
assert.strictEqual(stdout, '');
assert.strictEqual(stderr, '');
assert.strictEqual(code, 0);
}));
// Make sure that monkey-patching process.execArgv doesn't cause child_process
// to incorrectly munge execArgv.
child.exec(
`${nodejs} -e "process.execArgv = ['-e', 'console.log(42)', 'thirdArg'];` +
`require('child_process').fork('${emptyFile}')"`,
common.mustSucceed((stdout, stderr) => {
common.spawnPromisified(process.execPath, [
'-e',
'process.execArgv = [\'-e\', \'console.log(42)\', \'thirdArg\'];' +
`require('child_process').fork(${JSON.stringify(emptyFile)})`,
]).then(common.mustCall(({ stdout, stderr, code }) => {
assert.strictEqual(stdout, '42\n');
assert.strictEqual(stderr, '');
assert.strictEqual(code, 0);
}));
}
@ -192,28 +188,30 @@ child.exec(`${nodejs} --use-strict -p process.execArgv`,
].forEach(function(args) {
// Ensure that arguments are successfully passed to eval.
const opt = ' --eval "console.log(process.argv.slice(1).join(\' \'))"';
const cmd = `${nodejs}${opt} -- ${args}`;
child.exec(cmd, common.mustCall(function(err, stdout, stderr) {
child.exec(
...common.escapePOSIXShell`"${process.execPath}" --eval "console.log(process.argv.slice(1).join(' '))" -- ${args}`,
common.mustCall(function(err, stdout, stderr) {
assert.strictEqual(stdout, `${args}\n`);
assert.strictEqual(stderr, '');
assert.strictEqual(err, null);
}));
})
);
// Ensure that arguments are successfully passed to print.
const popt = ' --print "process.argv.slice(1).join(\' \')"';
const pcmd = `${nodejs}${popt} -- ${args}`;
child.exec(pcmd, common.mustCall(function(err, stdout, stderr) {
child.exec(
...common.escapePOSIXShell`"${process.execPath}" --print "process.argv.slice(1).join(' ')" -- ${args}`,
common.mustCall(function(err, stdout, stderr) {
assert.strictEqual(stdout, `${args}\n`);
assert.strictEqual(stderr, '');
assert.strictEqual(err, null);
}));
})
);
// Ensure that arguments are successfully passed to a script.
// The first argument after '--' should be interpreted as a script
// filename.
const filecmd = `${nodejs} -- "${__filename}" ${args}`;
child.exec(filecmd, common.mustCall(function(err, stdout, stderr) {
child.exec(...common.escapePOSIXShell`"${process.execPath}" -- "${__filename}" ${args}`,
common.mustCall(function(err, stdout, stderr) {
assert.strictEqual(stdout, `${args}\n`);
assert.strictEqual(stderr, '');
assert.strictEqual(err, null);
@ -226,14 +224,14 @@ child.exec(`${nodejs} --use-strict -p process.execArgv`,
// Assert that "42\n" is written to stdout on module eval.
const execOptions = '--input-type module';
child.exec(
`${nodejs} ${execOptions} --eval "console.log(42)"`,
...common.escapePOSIXShell`"${process.execPath}" ${execOptions} --eval "console.log(42)"`,
common.mustSucceed((stdout) => {
assert.strictEqual(stdout, '42\n');
}));
// Assert that "42\n" is written to stdout with print option.
child.exec(
`${nodejs} ${execOptions} --print --eval "42"`,
...common.escapePOSIXShell`"${process.execPath}" ${execOptions} --print --eval "42"`,
common.mustCall((err, stdout, stderr) => {
assert.ok(err);
assert.strictEqual(stdout, '');
@ -242,7 +240,7 @@ child.exec(
// Assert that error is written to stderr on invalid input.
child.exec(
`${nodejs} ${execOptions} --eval "!!!!"`,
...common.escapePOSIXShell`"${process.execPath}" ${execOptions} --eval "!!!!"`,
common.mustCall((err, stdout, stderr) => {
assert.ok(err);
assert.strictEqual(stdout, '');
@ -251,22 +249,25 @@ child.exec(
// Assert that require is undefined in ESM support
child.exec(
`${nodejs} ${execOptions} --eval "console.log(typeof require);"`,
...common.escapePOSIXShell`"${process.execPath}" ${execOptions} --eval "console.log(typeof require);"`,
common.mustSucceed((stdout) => {
assert.strictEqual(stdout, 'undefined\n');
}));
// Assert that import.meta is defined in ESM
child.exec(
`${nodejs} ${execOptions} --eval "console.log(typeof import.meta);"`,
...common.escapePOSIXShell`"${process.execPath}" ${execOptions} --eval "console.log(typeof import.meta);"`,
common.mustSucceed((stdout) => {
assert.strictEqual(stdout, 'object\n');
}));
{
// Assert that packages can be imported cwd-relative with --eval
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" ${execOptions} --eval`;
const options = { ...opts, cwd: path.join(__dirname, '../..') };
child.exec(
`${nodejs} ${execOptions} ` +
'--eval "import \'./test/fixtures/es-modules/mjs-file.mjs\'"',
`${cmd} "import './test/fixtures/es-modules/mjs-file.mjs'"`,
options,
common.mustSucceed((stdout) => {
assert.strictEqual(stdout, '.mjs file\n');
}));
@ -274,77 +275,69 @@ child.exec(
// Assert that packages can be dynamic imported initial cwd-relative with --eval
child.exec(
`${nodejs} ${execOptions} ` +
'--eval "process.chdir(\'..\');' +
cmd + ' "process.chdir(\'..\');' +
'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"',
options,
common.mustSucceed((stdout) => {
assert.strictEqual(stdout, '.mjs file\n');
}));
child.exec(
`${nodejs} ` +
'--eval "process.chdir(\'..\');' +
cmd + ' "process.chdir(\'..\');' +
'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"',
options,
common.mustSucceed((stdout) => {
assert.strictEqual(stdout, '.mjs file\n');
}));
}
if (common.hasCrypto) {
// Assert that calls to crypto utils work without require.
child.exec(
`${nodejs} ` +
'-e "console.log(crypto.randomBytes(16).toString(\'hex\'))"',
...common.escapePOSIXShell`"${process.execPath}" -e "console.log(crypto.randomBytes(16).toString('hex'))"`,
common.mustSucceed((stdout) => {
assert.match(stdout, /[0-9a-f]{32}/i);
}));
child.exec(
`${nodejs} ` +
'-p "crypto.randomBytes(16).toString(\'hex\')"',
...common.escapePOSIXShell`"${process.execPath}" -p "crypto.randomBytes(16).toString('hex')"`,
common.mustSucceed((stdout) => {
assert.match(stdout, /[0-9a-f]{32}/i);
}));
}
// Assert that overriding crypto works.
child.exec(
`${nodejs} ` +
'-p "crypto=Symbol(\'test\')"',
...common.escapePOSIXShell`"${process.execPath}" -p "crypto=Symbol('test')"`,
common.mustSucceed((stdout) => {
assert.match(stdout, /Symbol\(test\)/i);
}));
child.exec(
`${nodejs} ` +
'-e "crypto = {};console.log(\'randomBytes\', typeof crypto.randomBytes)"',
...common.escapePOSIXShell`"${process.execPath}" -e "crypto = {};console.log('randomBytes', typeof crypto.randomBytes)"`,
common.mustSucceed((stdout) => {
assert.match(stdout, /randomBytes\sundefined/);
}));
// Assert that overriding crypto with a local variable works.
child.exec(
`${nodejs} ` +
'-e "const crypto = {};console.log(\'randomBytes\', typeof crypto.randomBytes)"',
...common.escapePOSIXShell`"${process.execPath}" -e "const crypto = {};console.log('randomBytes', typeof crypto.randomBytes)"`,
common.mustSucceed((stdout) => {
assert.match(stdout, /randomBytes\sundefined/);
}));
child.exec(
`${nodejs} ` +
'-e "let crypto = {};console.log(\'randomBytes\', typeof crypto.randomBytes)"',
...common.escapePOSIXShell`"${process.execPath}" -e "let crypto = {};console.log('randomBytes', typeof crypto.randomBytes)"`,
common.mustSucceed((stdout) => {
assert.match(stdout, /randomBytes\sundefined/);
}));
child.exec(
`${nodejs} ` +
'-e "var crypto = {};console.log(\'randomBytes\', typeof crypto.randomBytes)"',
...common.escapePOSIXShell`"${process.execPath}" -e "var crypto = {};console.log('randomBytes', typeof crypto.randomBytes)"`,
common.mustSucceed((stdout) => {
assert.match(stdout, /randomBytes\sundefined/);
}));
child.exec(
`${nodejs} ` +
'-p "const crypto = {randomBytes:1};typeof crypto.randomBytes"',
...common.escapePOSIXShell`"${process.execPath}" -p "const crypto = {randomBytes:1};typeof crypto.randomBytes"`,
common.mustSucceed((stdout) => {
assert.match(stdout, /^number/);
}));
child.exec(
`${nodejs} ` +
'-p "let crypto = {randomBytes:1};typeof crypto.randomBytes"',
...common.escapePOSIXShell`"${process.execPath}" -p "let crypto = {randomBytes:1};typeof crypto.randomBytes"`,
common.mustSucceed((stdout) => {
assert.match(stdout, /^number/);
}));

View File

@ -11,18 +11,8 @@ const { exec, spawn } = require('child_process');
const { once } = require('events');
let stdOut;
// The execPath might contain chars that should be escaped in a shell context.
// On non-Windows, we can pass the path via the env; `"` is not a valid char on
// Windows, so we can simply pass the path.
const execNode = (args, callback) => exec(
`"${common.isWindows ? process.execPath : '$NODE'}" ${args}`,
common.isWindows ? undefined : { env: { ...process.env, NODE: process.execPath } },
callback,
);
function startPrintHelpTest() {
execNode('--help', common.mustSucceed((stdout, stderr) => {
exec(...common.escapePOSIXShell`"${process.execPath}" --help`, common.mustSucceed((stdout, stderr) => {
stdOut = stdout;
validateNodePrintHelp();
}));

View File

@ -4,21 +4,10 @@ const common = require('../common');
const assert = require('assert');
const { exec } = require('child_process');
// The execPath might contain chars that should be escaped in a shell context.
// On non-Windows, we can pass the path via the env; `"` is not a valid char on
// Windows, so we can simply pass the path.
const execNode = (args, callback) => exec(
`"${common.isWindows ? process.execPath : '$NODE'}" ${args}`,
common.isWindows ? undefined : { env: { ...process.env, NODE: process.execPath } },
callback,
);
// Should throw if -c and -e flags are both passed
['-c', '--check'].forEach(function(checkFlag) {
['-e', '--eval'].forEach(function(evalFlag) {
const args = [checkFlag, evalFlag, 'foo'];
execNode(args.join(' '), common.mustCall((err, stdout, stderr) => {
exec(...common.escapePOSIXShell`"${process.execPath}" ${checkFlag} ${evalFlag} foo`, common.mustCall((err, stdout, stderr) => {
assert.strictEqual(err instanceof Error, true);
assert.strictEqual(err.code, 9);
assert(

View File

@ -621,12 +621,10 @@ assert.throws(
const msgfile = tmpdir.resolve('s5.msg');
fs.writeFileSync(msgfile, msg);
const cmd =
`"${common.opensslCli}" dgst -sha256 -verify "${pubfile}" -signature "${
sigfile}" -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-2 "${
msgfile}"`;
exec(cmd, common.mustCall((err, stdout, stderr) => {
exec(...common.escapePOSIXShell`"${
common.opensslCli}" dgst -sha256 -verify "${pubfile}" -signature "${
sigfile}" -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-2 "${msgfile
}"`, common.mustCall((err, stdout, stderr) => {
assert(stdout.includes('Verified OK'));
}));
}

View File

@ -202,18 +202,15 @@ if (process.argv[2] === 'child') {
} else {
tests.forEach(function(test, testIndex) {
let testCmd = '';
const escapedArgs = common.escapePOSIXShell`"${process.execPath}" --abort-on-uncaught-exception "${__filename}" child ${testIndex}`;
if (!common.isWindows) {
// Do not create core files, as it can take a lot of disk space on
// continuous testing and developers' machines
testCmd += 'ulimit -c 0 && ';
escapedArgs[0] = 'ulimit -c 0 && ' + escapedArgs[0];
}
testCmd += `"${process.argv[0]}" --abort-on-uncaught-exception ` +
`"${process.argv[1]}" child ${testIndex}`;
try {
child_process.execSync(testCmd);
child_process.execSync(...escapedArgs);
} catch (e) {
assert.fail(`Test index ${testIndex} failed: ${e}`);
}

View File

@ -50,7 +50,7 @@ if (process.argv[2] === 'child') {
function runTestWithoutAbortOnUncaughtException() {
child_process.exec(
createTestCmdLine(),
...createTestCmdLine(),
function onTestDone(err, stdout, stderr) {
// When _not_ passing --abort-on-uncaught-exception, the process'
// uncaughtException handler _must_ be called, and thus the error
@ -70,7 +70,7 @@ function runTestWithoutAbortOnUncaughtException() {
}
function runTestWithAbortOnUncaughtException() {
child_process.exec(createTestCmdLine({
child_process.exec(...createTestCmdLine({
withAbortOnUncaughtException: true
}), function onTestDone(err, stdout, stderr) {
assert.notStrictEqual(err.code, RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE,
@ -82,21 +82,14 @@ function runTestWithAbortOnUncaughtException() {
}
function createTestCmdLine(options) {
let testCmd = '';
const escapedArgs = common.escapePOSIXShell`"${process.execPath}" ${
options?.withAbortOnUncaughtException ? '--abort-on-uncaught-exception' : ''
} "${__filename}" child`;
if (!common.isWindows) {
// Do not create core files, as it can take a lot of disk space on
// continuous testing and developers' machines
testCmd += 'ulimit -c 0 && ';
escapedArgs[0] = 'ulimit -c 0 && ' + escapedArgs[0];
}
testCmd += `"${process.argv[0]}"`;
if (options?.withAbortOnUncaughtException) {
testCmd += ' --abort-on-uncaught-exception';
}
testCmd += ` "${process.argv[1]}" child`;
return testCmd;
return escapedArgs;
}

View File

@ -91,21 +91,17 @@ if (process.argv[2] === 'child') {
if (options.throwInDomainErrHandler)
throwInDomainErrHandlerOpt = 'throwInDomainErrHandler';
let cmdToExec = '';
if (!common.isWindows) {
// Do not create core files, as it can take a lot of disk space on
// continuous testing and developers' machines
cmdToExec += 'ulimit -c 0 && ';
}
let useTryCatchOpt;
if (options.useTryCatch)
useTryCatchOpt = 'useTryCatch';
cmdToExec += `"${process.argv[0]}" ${cmdLineOption ? cmdLineOption : ''} "${
process.argv[1]}" child ${throwInDomainErrHandlerOpt} ${useTryCatchOpt}`;
const child = exec(cmdToExec);
const escapedArgs = common.escapePOSIXShell`"${process.execPath}" ${cmdLineOption || ''} "${__filename}" child ${throwInDomainErrHandlerOpt || ''} ${useTryCatchOpt || ''}`;
if (!common.isWindows) {
// Do not create core files, as it can take a lot of disk space on
// continuous testing and developers' machines
escapedArgs[0] = 'ulimit -c 0 && ' + escapedArgs[0];
}
const child = exec(...escapedArgs);
if (child) {
child.on('exit', function onChildExited(exitCode, signal) {

View File

@ -7,14 +7,13 @@ if (process.argv[2] === 'child') {
process.emitWarning('foo');
} else {
function test(newEnv) {
const env = { ...process.env, ...newEnv };
const cmd = `"${process.execPath}" "${__filename}" child`;
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
cp.exec(cmd, { env }, common.mustCall((err, stdout, stderr) => {
cp.exec(cmd, { ...opts, env: { ...opts?.env, ...newEnv } }, common.mustCall((err, stdout, stderr) => {
assert.strictEqual(err, null);
assert.strictEqual(stdout, '');
if (env.NODE_NO_WARNINGS === '1')
if (newEnv.NODE_NO_WARNINGS === '1')
assert.strictEqual(stderr, '');
else
assert.match(stderr.trim(), /Warning: foo\n/);

View File

@ -28,8 +28,7 @@ const fixtures = require('../common/fixtures');
function errExec(script, option, callback) {
callback = typeof option === 'function' ? option : callback;
option = typeof option === 'string' ? option : '';
const cmd = `"${process.argv[0]}" ${option} "${fixtures.path(script)}"`;
return exec(cmd, (err, stdout, stderr) => {
return exec(...common.escapePOSIXShell`"${process.execPath}" ${option} "${fixtures.path(script)}"`, (err, stdout, stderr) => {
// There was some error
assert.ok(err);

View File

@ -198,7 +198,7 @@ if (!common.isWindows) {
const filename = `${tmpdir.path}/foo.pipe`;
const mkfifoResult = child_process.spawnSync('mkfifo', [filename]);
if (!mkfifoResult.error) {
child_process.exec(`echo "xyz foobar" > '${filename}'`);
child_process.exec(...common.escapePOSIXShell`echo "xyz foobar" > "${filename}"`);
const stream = new fs.createReadStream(filename, common.mustNotMutateObjectDeep({ end: 1 }));
stream.data = '';

View File

@ -25,12 +25,10 @@ const data2 = 'World';
const expected = `${data1}\n${data2}\n`;
const exec = require('child_process').exec;
const f = JSON.stringify(__filename);
const node = JSON.stringify(process.execPath);
function test(child) {
const cmd = `(echo ${data1}; sleep 0.5; echo ${data2}) | ${node} ${f} ${child}`;
exec(cmd, common.mustSucceed((stdout, stderr) => {
exec(...common.escapePOSIXShell`(echo "${data1}"; sleep 0.5; echo "${data2}") | "${process.execPath}" "${__filename}" "${child}"`,
common.mustSucceed((stdout, stderr) => {
assert.strictEqual(
stdout,
expected,

View File

@ -36,9 +36,7 @@ const fixtures = require('../common/fixtures');
function test(env, cb) {
const filename = fixtures.path('test-fs-readfile-error.js');
const execPath = `"${process.execPath}" "${filename}"`;
const options = { env: { ...process.env, ...env } };
exec(execPath, options, (err, stdout, stderr) => {
exec(...common.escapePOSIXShell`"${process.execPath}" "${filename}"`, (err, stdout, stderr) => {
assert(err);
assert.strictEqual(stdout, '');
assert.notStrictEqual(stderr, '');

View File

@ -25,10 +25,8 @@ tmpdir.refresh();
fs.writeFileSync(filename, dataExpected);
const exec = require('child_process').exec;
const f = JSON.stringify(__filename);
const node = JSON.stringify(process.execPath);
const cmd = `cat ${filename} | ${node} ${f} child`;
exec(cmd, { maxBuffer: 1000000 }, common.mustSucceed((stdout, stderr) => {
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child < "${filename}"`;
exec(cmd, { ...opts, maxBuffer: 1000000 }, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(
stdout,
dataExpected,

View File

@ -43,10 +43,7 @@ const filename = fixtures.path('readfile_pipe_test.txt');
const dataExpected = fs.readFileSync(filename).toString();
const exec = require('child_process').exec;
const f = JSON.stringify(__filename);
const node = JSON.stringify(process.execPath);
const cmd = `cat ${filename} | ${node} ${f} child`;
exec(cmd, common.mustSucceed((stdout, stderr) => {
exec(...common.escapePOSIXShell`"${process.execPath}" "${__filename}" child < "${filename}"`, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(
stdout,
dataExpected,

View File

@ -22,12 +22,10 @@ tmpdir.refresh();
fs.writeFileSync(filename, dataExpected);
const exec = require('child_process').exec;
const f = JSON.stringify(__filename);
const node = JSON.stringify(process.execPath);
const cmd = `cat ${filename} | ${node} ${f} child`;
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child < "${filename}"`;
exec(
cmd,
{ maxBuffer: 1000000 },
{ ...opts, maxBuffer: 1_000_000 },
common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, dataExpected);
assert.strictEqual(stderr, '');

View File

@ -19,8 +19,8 @@ if (process.argv[2] === 'child') {
tmpdir.refresh();
fs.writeFileSync(filename, '.'.repeat(1 << 16)); // Exceeds RLIMIT_FSIZE.
} else {
const cmd = `ulimit -f 1 && '${process.execPath}' '${__filename}' child`;
const result = child_process.spawnSync('/bin/sh', ['-c', cmd]);
const [cmd, opts] = common.escapePOSIXShell`ulimit -f 1 && "${process.execPath}" "${__filename}" child`;
const result = child_process.spawnSync('/bin/sh', ['-c', cmd], opts);
const haystack = result.stderr.toString();
const needle = 'Error: EFBIG: file too large, write';
const ok = haystack.includes(needle);

View File

@ -15,20 +15,12 @@ if (process.argv[2] === 'child') {
assert.ok(process.permission.has('child'));
}
// The execPath might contain chars that should be escaped in a shell context.
// On non-Windows, we can pass the path via the env; `"` is not a valid char on
// Windows, so we can simply pass the path.
const execNode = (args) => childProcess.execSync(
`"${common.isWindows ? process.execPath : '$NODE'}" ${args}`,
common.isWindows ? undefined : { env: { ...process.env, NODE: process.execPath } },
);
// When a permission is set by cli, the process shouldn't be able
// to spawn unless --allow-child-process is sent
{
// doesNotThrow
childProcess.spawnSync(process.execPath, ['--version']);
execNode('--version');
childProcess.execSync(...common.escapePOSIXShell`"${process.execPath}" --version`);
childProcess.fork(__filename, ['child']);
childProcess.execFileSync(process.execPath, ['--version']);
}

View File

@ -15,14 +15,6 @@ if (process.argv[2] === 'child') {
assert.ok(!process.permission.has('child'));
}
// The execPath might contain chars that should be escaped in a shell context.
// On non-Windows, we can pass the path via the env; `"` is not a valid char on
// Windows, so we can simply pass the path.
const execNode = (args) => [
`"${common.isWindows ? process.execPath : '$NODE'}" ${args}`,
common.isWindows ? undefined : { env: { ...process.env, NODE: process.execPath } },
];
// When a permission is set by cli, the process shouldn't be able
// to spawn
{
@ -39,13 +31,13 @@ const execNode = (args) => [
permission: 'ChildProcess',
}));
assert.throws(() => {
childProcess.exec(...execNode('--version'));
childProcess.exec(...common.escapePOSIXShell`"${process.execPath}" --version`);
}, common.expectsError({
code: 'ERR_ACCESS_DENIED',
permission: 'ChildProcess',
}));
assert.throws(() => {
childProcess.execSync(...execNode('--version'));
childProcess.execSync(...common.escapePOSIXShell`"${process.execPath}" --version`);
}, common.expectsError({
code: 'ERR_ACCESS_DENIED',
permission: 'ChildProcess',
@ -57,13 +49,13 @@ const execNode = (args) => [
permission: 'ChildProcess',
}));
assert.throws(() => {
childProcess.execFile(...execNode('--version'));
childProcess.execFile(...common.escapePOSIXShell`"${process.execPath}" --version`);
}, common.expectsError({
code: 'ERR_ACCESS_DENIED',
permission: 'ChildProcess',
}));
assert.throws(() => {
childProcess.execFileSync(...execNode('--version'));
childProcess.execFileSync(...common.escapePOSIXShell`"${process.execPath}" --version`);
}, common.expectsError({
code: 'ERR_ACCESS_DENIED',
permission: 'ChildProcess',

View File

@ -13,8 +13,8 @@ if (!common.isMainThread)
const selfRefModule = fixtures.path('self_ref_module');
const fixtureA = fixtures.path('printA.js');
exec(`"${nodeBinary}" -r self_ref "${fixtureA}"`, { cwd: selfRefModule },
(err, stdout, stderr) => {
assert.ifError(err);
const [cmd, opts] = common.escapePOSIXShell`"${nodeBinary}" -r self_ref "${fixtureA}"`;
exec(cmd, { ...opts, cwd: selfRefModule },
common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, 'A\n');
});
}));

View File

@ -7,4 +7,4 @@ const { exec } = require('child_process');
const kNodeBinary = process.argv[0];
exec(`"${kNodeBinary}" -r "${worker}" -pe "1+1"`, common.mustSucceed());
exec(...common.escapePOSIXShell`"${kNodeBinary}" -r "${worker}" -pe "1+1"`, common.mustSucceed());

View File

@ -10,15 +10,11 @@ const stdoutScript = fixtures.path('echo-close-check.js');
const tmpFile = tmpdir.resolve('stdin.txt');
const string = fixtures.utf8TestText;
const cmd = `"${process.argv[0]}" "${stdoutScript}" < "${tmpFile}"`;
tmpdir.refresh();
console.log(`${cmd}\n\n`);
fs.writeFileSync(tmpFile, string);
childProcess.exec(cmd, common.mustCall(function(err, stdout, stderr) {
childProcess.exec(...common.escapePOSIXShell`"${process.argv0}" "${stdoutScript}" < "${tmpFile}"`, common.mustCall(function(err, stdout, stderr) {
fs.unlinkSync(tmpFile);
assert.ifError(err);

View File

@ -29,8 +29,8 @@ if (process.argv[2] === 'child') {
}
// Run the script in a shell but close stdout and stderr.
const cmd = `"${process.execPath}" "${__filename}" child 1>&- 2>&-`;
const proc = spawn('/bin/sh', ['-c', cmd], { stdio: 'inherit' });
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child 1>&- 2>&-`;
const proc = spawn('/bin/sh', ['-c', cmd], { ...opts, stdio: 'inherit' });
proc.on('exit', common.mustCall(function(exitCode) {
assert.strictEqual(exitCode, 0);

View File

@ -7,12 +7,9 @@ const { getSystemErrorName } = require('util');
const testScript = fixtures.path('catch-stdout-error.js');
const cmd = `${JSON.stringify(process.execPath)} ` +
`${JSON.stringify(testScript)} | ` +
`${JSON.stringify(process.execPath)} ` +
'-pe "process.stdin.on(\'data\' , () => process.exit(1))"';
const child = child_process.exec(cmd);
const child = child_process.exec(
...common.escapePOSIXShell`"${process.execPath}" "${testScript}" | "${process.execPath}" -pe "process.stdin.on('data' , () => process.exit(1))"`
);
let output = '';
child.stderr.on('data', function(c) {
@ -21,12 +18,7 @@ child.stderr.on('data', function(c) {
child.on('close', common.mustCall(function(code) {
try {
output = JSON.parse(output);
} catch {
console.error(output);
process.exit(1);
}
assert.strictEqual(output.code, 'EPIPE');
assert.strictEqual(getSystemErrorName(output.errno), 'EPIPE');

View File

@ -13,9 +13,6 @@ const tmpFile = tmpdir.resolve('stdout.txt');
tmpdir.refresh();
function test(size, useBuffer, cb) {
const cmd = `"${process.argv[0]}" "${
useBuffer ? scriptBuffer : scriptString}" ${size} > "${tmpFile}"`;
try {
fs.unlinkSync(tmpFile);
} catch {
@ -24,7 +21,9 @@ function test(size, useBuffer, cb) {
console.log(`${size} chars to ${tmpFile}...`);
childProcess.exec(cmd, common.mustSucceed(() => {
childProcess.exec(...common.escapePOSIXShell`"${
process.execPath}" "${useBuffer ? scriptBuffer : scriptString}" ${size} > "${tmpFile
}"`, common.mustSucceed(() => {
console.log('done!');
const stat = fs.statSync(tmpFile);

View File

@ -13,14 +13,7 @@ if (process.argv[2] === 'child') {
);
} else {
const cp = require('child_process');
cp.exec([
'echo',
'hello',
'|',
`"${process.execPath}"`,
`"${__filename}"`,
'child',
].join(' '), common.mustSucceed((stdout) => {
cp.exec(...common.escapePOSIXShell`echo hello | "${process.execPath}" "${__filename}" child`, common.mustSucceed((stdout) => {
assert.strictEqual(stdout.split(os.EOL).shift().trim(), 'hello');
}));
}

View File

@ -49,10 +49,10 @@ const server = tls.createServer(options, common.mustCall(function(conn) {
}));
server.listen(0, '127.0.0.1', common.mustCall(function() {
const cmd = `"${common.opensslCli}" s_client -cipher ${
const cmd = common.escapePOSIXShell`"${common.opensslCli}" s_client -cipher ${
options.ciphers} -connect 127.0.0.1:${this.address().port}`;
exec(cmd, common.mustSucceed((stdout, stderr) => {
exec(...cmd, common.mustSucceed((stdout, stderr) => {
assert(stdout.includes(reply));
server.close();
}));

View File

@ -47,9 +47,7 @@ if (process.argv[2] === 'child') {
} else {
// Limit the number of open files, to force workers to fail.
let testCmd = `ulimit -n ${OPENFILES} && `;
testCmd += `${process.execPath} ${__filename} child`;
const cp = child_process.exec(testCmd);
const cp = child_process.exec(...common.escapePOSIXShell`ulimit -n ${OPENFILES} && "${process.execPath}" "${__filename}" child`);
// Turn on the child streams for debugging purposes.
let stdout = '';

View File

@ -30,12 +30,14 @@ const fs = require('fs');
const ulimit = Number(child_process.execSync('ulimit -Hn'));
if (ulimit > 64 || Number.isNaN(ulimit)) {
const [cmd, opts] = common.escapePOSIXShell`ulimit -n 64 && "${process.execPath}" "${__filename}"`;
// Sorry about this nonsense. It can be replaced if
// https://github.com/nodejs/node-v0.x-archive/pull/2143#issuecomment-2847886
// ever happens.
const result = child_process.spawnSync(
'/bin/sh',
['-c', `ulimit -n 64 && '${process.execPath}' '${__filename}'`]
['-c', cmd],
opts,
);
assert.strictEqual(result.stdout.toString(), '');
assert.strictEqual(result.stderr.toString(), '');

View File

@ -1,16 +1,14 @@
'use strict';
require('../common');
const common = require('../common');
const { exec } = require('child_process');
const { test } = require('node:test');
const fixtures = require('../common/fixtures');
const node = process.execPath;
// Test both sets of arguments that check syntax
const syntaxArgs = [
['-c'],
['--check'],
'-c',
'--check',
];
// Match on the name of the `Error` but not the message as it is different
@ -27,13 +25,10 @@ const syntaxErrorRE = /^SyntaxError: \b/m;
const path = fixtures.path(file);
// Loop each possible option, `-c` or `--check`
syntaxArgs.forEach((args) => {
test(`Checking syntax for ${file} with ${args.join(' ')}`, async (t) => {
const _args = args.concat(path);
const cmd = [node, ..._args].join(' ');
syntaxArgs.forEach((flag) => {
test(`Checking syntax for ${file} with ${flag}`, async (t) => {
try {
const { stdout, stderr } = await execPromise(cmd);
const { stdout, stderr } = await execNode(flag, path);
// No stdout should be produced
t.assert.strictEqual(stdout, '');
@ -51,9 +46,9 @@ const syntaxErrorRE = /^SyntaxError: \b/m;
});
// Helper function to promisify exec
function execPromise(cmd) {
function execNode(flag, path) {
const { promise, resolve, reject } = Promise.withResolvers();
exec(cmd, (err, stdout, stderr) => {
exec(...common.escapePOSIXShell`"${process.execPath}" ${flag} "${path}"`, (err, stdout, stderr) => {
if (err) return reject({ ...err, stdout, stderr });
resolve({ stdout, stderr });
});

View File

@ -5,15 +5,6 @@ const assert = require('assert');
const { exec } = require('child_process');
const fixtures = require('../common/fixtures');
// The execPath might contain chars that should be escaped in a shell context.
// On non-Windows, we can pass the path via the env; `"` is not a valid char on
// Windows, so we can simply pass the path.
const execNode = (flag, file, callback) => exec(
`"${common.isWindows ? process.execPath : '$NODE'}" ${flag} "${common.isWindows ? file : '$FILE'}"`,
common.isWindows ? undefined : { env: { ...process.env, NODE: process.execPath, FILE: file } },
callback,
);
// Test both sets of arguments that check syntax
const syntaxArgs = [
'-c',
@ -31,7 +22,7 @@ const notFoundRE = /^Error: Cannot find module/m;
// Loop each possible option, `-c` or `--check`
syntaxArgs.forEach(function(flag) {
execNode(flag, file, common.mustCall((err, stdout, stderr) => {
exec(...common.escapePOSIXShell`"${process.execPath}" ${flag} "${file}"`, common.mustCall((err, stdout, stderr) => {
// No stdout should be produced
assert.strictEqual(stdout, '');

View File

@ -5,15 +5,6 @@ const assert = require('assert');
const { exec } = require('child_process');
const fixtures = require('../common/fixtures');
// The execPath might contain chars that should be escaped in a shell context.
// On non-Windows, we can pass the path via the env; `"` is not a valid char on
// Windows, so we can simply pass the path.
const execNode = (flag, file, callback) => exec(
`"${common.isWindows ? process.execPath : '$NODE'}" ${flag} "${common.isWindows ? file : '$FILE'}"`,
common.isWindows ? undefined : { env: { ...process.env, NODE: process.execPath, FILE: file } },
callback,
);
// Test both sets of arguments that check syntax
const syntaxArgs = [
'-c',
@ -33,7 +24,7 @@ const syntaxArgs = [
// Loop each possible option, `-c` or `--check`
syntaxArgs.forEach(function(flag) {
execNode(flag, file, common.mustCall((err, stdout, stderr) => {
exec(...common.escapePOSIXShell`"${process.execPath}" ${flag} "${file}"`, common.mustCall((err, stdout, stderr) => {
if (err) {
console.log('-- stdout --');
console.log(stdout);

View File

@ -35,8 +35,7 @@ if (process.env.TEST_INIT) {
process.env.TEST_INIT = 1;
function test(file, expected) {
const path = `"${process.execPath}" ${file}`;
child.exec(path, { env: process.env }, common.mustSucceed((out) => {
child.exec(...common.escapePOSIXShell`"${process.execPath}" "${file}"`, common.mustSucceed((out) => {
assert.strictEqual(out, expected, `'node ${file}' failed!`);
}));
}