Skip to content

Commit 04b9b19

Browse files
committed
test: add escapePOSIXShell util
1 parent 0f7bdcc commit 04b9b19

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+237
-338
lines changed

test/abort/test-abort-fatal-error.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ if (common.isWindows)
2727
const assert = require('assert');
2828
const exec = require('child_process').exec;
2929

30-
let cmdline = `ulimit -c 0; ${process.execPath}`;
31-
cmdline += ' --max-old-space-size=16 --max-semi-space-size=4';
32-
cmdline += ' -e "a = []; for (i = 0; i < 1e9; i++) { a.push({}) }"';
30+
const cmdline =
31+
common.escapePOSIXShell`ulimit -c 0; "${
32+
process.execPath
33+
}" --max-old-space-size=16 --max-semi-space-size=4 -e "a = []; for (i = 0; i < 1e9; i++) { a.push({}) }"`;
3334

34-
exec(cmdline, function(err, stdout, stderr) {
35-
if (!err) {
36-
console.log(stdout);
37-
console.log(stderr);
38-
assert(false, 'this test should fail');
35+
exec(...cmdline, common.mustCall((err, stdout, stderr) => {
36+
if (err?.code !== 134 && err?.signal !== 'SIGABRT') {
37+
console.log({ err, stdout, stderr });
38+
assert.fail(err?.message);
3939
}
4040

4141
assert(common.nodeProcessAborted(err.code, err.signal));
42-
});
42+
}));

test/async-hooks/test-callback-error.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,12 @@ assert.ok(!arg);
6262
let program = process.execPath;
6363
let args = [
6464
'--abort-on-uncaught-exception', __filename, 'test_callback_abort' ];
65-
const options = { encoding: 'utf8' };
65+
let options = { encoding: 'utf8' };
6666
if (!common.isWindows) {
67-
program = `ulimit -c 0 && exec ${program} ${args.join(' ')}`;
67+
[program, options] = common.escapePOSIXShell`ulimit -c 0 && exec "${program}" ${args[0]} "${args[1]}" ${args[2]}`;
6868
args = [];
6969
options.shell = true;
70+
options.encoding = 'utf8';
7071
}
7172
const child = spawnSync(program, args, options);
7273
if (common.isWindows) {

test/common/index.js

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -249,15 +249,13 @@ const PIPE = (() => {
249249
// `$node --abort-on-uncaught-exception $file child`
250250
// the process aborts.
251251
function childShouldThrowAndAbort() {
252-
let testCmd = '';
252+
const escapedArgs = escapePOSIXShell`"${process.argv[0]}" --abort-on-uncaught-exception "${process.argv[1]}" child`;
253253
if (!isWindows) {
254254
// Do not create core files, as it can take a lot of disk space on
255255
// continuous testing and developers' machines
256-
testCmd += 'ulimit -c 0 && ';
256+
escapedArgs[0] = 'ulimit -c 0 && ' + escapedArgs[0];
257257
}
258-
testCmd += `"${process.argv[0]}" --abort-on-uncaught-exception `;
259-
testCmd += `"${process.argv[1]}" child`;
260-
const child = exec(testCmd);
258+
const child = exec(...escapedArgs);
261259
child.on('exit', function onExit(exitCode, signal) {
262260
const errMsg = 'Test should have aborted ' +
263261
`but instead exited with exit code ${exitCode}` +
@@ -944,13 +942,40 @@ function expectRequiredModule(mod, expectation, checkESModule = true) {
944942
assert.deepStrictEqual(clone, { ...expectation });
945943
}
946944

945+
946+
/**
947+
* Escape quoted values in a string template literal. On Windows, this function
948+
* does not escape anything (which is fine for paths, as `"` is not a valid char
949+
* in a path on Windows), so you should use it only to escape paths – or other
950+
* values on tests which are skipped on Windows.
951+
* @returns {[string, object | undefined]} An array that can be passed as
952+
* arguments to `exec` or `execSync`.
953+
*/
954+
function escapePOSIXShell(cmdParts, ...args) {
955+
if (common.isWindows) {
956+
// On Windows, paths cannot contain `"`, so we can return the string unchanged.
957+
return [String.raw({ raw: cmdParts }, ...args)];
958+
}
959+
// On POSIX shells, we can pass values via the env, as there's a standard way for referencing a variable.
960+
const env = { ...process.env };
961+
let cmd = cmdParts[0];
962+
for (let i = 0; i < args.length; i++) {
963+
const envVarName = `ESCAPED_${i}`;
964+
env[envVarName] = args[i];
965+
cmd += '${' + envVarName + '}' + cmdParts[i + 1];
966+
}
967+
968+
return [cmd, { env }];
969+
}
970+
947971
const common = {
948972
allowGlobals,
949973
buildType,
950974
canCreateSymLink,
951975
childShouldThrowAndAbort,
952976
createZeroFilledFile,
953977
defaultAutoSelectFamilyAttemptTimeout,
978+
escapePOSIXShell,
954979
expectsError,
955980
expectRequiredModule,
956981
expectWarning,

test/common/index.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const {
1111
childShouldThrowAndAbort,
1212
createZeroFilledFile,
1313
enoughTestMem,
14+
escapePOSIXShell,
1415
expectsError,
1516
expectWarning,
1617
getArrayBufferViews,
@@ -64,6 +65,7 @@ export {
6465
createRequire,
6566
createZeroFilledFile,
6667
enoughTestMem,
68+
escapePOSIXShell,
6769
expectsError,
6870
expectWarning,
6971
getArrayBufferViews,

test/fixtures/snapshot/child-process-sync.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const {
88
function spawn() {
99
const { spawnSync, execFileSync, execSync } = require('child_process');
1010
spawnSync(process.execPath, [ __filename, 'spawnSync' ], { stdio: 'inherit' });
11-
execSync(`"${process.execPath}" "${__filename}" "execSync"`, { stdio: 'inherit' });
11+
execSync(`"$NODE" "$FILE" "execSync"`, { stdio: 'inherit', env: { ...process.env, NODE: process.execPath, FILE: __filename } });
1212
execFileSync(process.execPath, [ __filename, 'execFileSync' ], { stdio: 'inherit' });
1313
}
1414

test/parallel/test-child-process-bad-stdio.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ ChildProcess.prototype.spawn = function() {
2727
};
2828

2929
function createChild(options, callback) {
30-
const cmd = `"${process.execPath}" "${__filename}" child`;
30+
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
31+
options = { ...options, env: { ...opts.env, ...options.env } };
3132

3233
return cp.exec(cmd, options, common.mustCall(callback));
3334
}

test/parallel/test-child-process-exec-encoding.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ if (process.argv[2] === 'child') {
1313
const expectedStdout = `${stdoutData}\n`;
1414
const expectedStderr = `${stderrData}\n`;
1515
function run(options, callback) {
16-
const cmd = `"${process.execPath}" "${__filename}" child`;
16+
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
17+
options = { ...options, env: { ...opts.env, ...options.env } };
1718

1819
cp.exec(cmd, options, common.mustSucceed((stdout, stderr) => {
1920
callback(stdout, stderr);

test/parallel/test-child-process-exec-maxbuf.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ function runChecks(err, stdio, streamName, expected) {
1414
// On non-Windows, we can pass the path via the env; `"` is not a valid char on
1515
// Windows, so we can simply pass the path.
1616
const execNode = (args, optionsOrCallback, callback) => {
17+
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" `;
1718
let options = optionsOrCallback;
1819
if (typeof optionsOrCallback === 'function') {
1920
options = undefined;
2021
callback = optionsOrCallback;
2122
}
2223
return cp.exec(
23-
`"${common.isWindows ? process.execPath : '$NODE'}" ${args}`,
24-
common.isWindows ? options : { ...options, env: { ...process.env, NODE: process.execPath } },
24+
cmd + args,
25+
{ ...opts, ...options },
2526
callback,
2627
);
2728
};

test/parallel/test-child-process-exec-std-encoding.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ if (process.argv[2] === 'child') {
1212
console.log(stdoutData);
1313
console.error(stderrData);
1414
} else {
15-
const cmd = `"${process.execPath}" "${__filename}" child`;
16-
const child = cp.exec(cmd, common.mustSucceed((stdout, stderr) => {
15+
const child = cp.exec(...common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`, common.mustSucceed((stdout, stderr) => {
1716
assert.strictEqual(stdout, expectedStdout);
1817
assert.strictEqual(stderr, expectedStderr);
1918
}));

test/parallel/test-child-process-exec-timeout-expire.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ if (process.argv[2] === 'child') {
1818
return;
1919
}
2020

21-
const cmd = `"${process.execPath}" "${__filename}" child`;
21+
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
2222

2323
cp.exec(cmd, {
24+
...opts,
2425
timeout: kExpiringParentTimer,
2526
}, common.mustCall((err, stdout, stderr) => {
2627
console.log('[stdout]', stdout.trim());

0 commit comments

Comments
 (0)