mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
99e0d0d218
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>
353 lines
13 KiB
JavaScript
353 lines
13 KiB
JavaScript
// Copyright Joyent, Inc. and other Node contributors.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
// following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included
|
|
// in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
'use strict';
|
|
if (module !== require.main) {
|
|
// Signal we've been loaded as a module.
|
|
// The following console.log() is part of the test.
|
|
console.log('Loaded as a module, exiting with status code 42.');
|
|
process.exit(42);
|
|
}
|
|
|
|
const common = require('../common');
|
|
const assert = require('assert');
|
|
const child = require('child_process');
|
|
const path = require('path');
|
|
const fixtures = require('../common/fixtures');
|
|
|
|
if (process.argv.length > 2) {
|
|
console.log(process.argv.slice(2).join(' '));
|
|
process.exit(0);
|
|
}
|
|
|
|
// Assert that nothing is written to stdout.
|
|
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(...common.escapePOSIXShell`"${process.execPath}" --eval "console.error(42)"`,
|
|
common.mustSucceed((stdout, stderr) => {
|
|
assert.strictEqual(stdout, '');
|
|
assert.strictEqual(stderr, '42\n');
|
|
}));
|
|
|
|
// Assert that the expected output is written to stdout.
|
|
['--print', '-p -e', '-pe', '-p'].forEach((s) => {
|
|
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" ${s}`;
|
|
|
|
child.exec(`${cmd} 42`, opts, common.mustSucceed((stdout, stderr) => {
|
|
assert.strictEqual(stdout, '42\n');
|
|
assert.strictEqual(stderr, '');
|
|
}));
|
|
|
|
child.exec(`${cmd} '[]'`, opts, common.mustSucceed((stdout, stderr) => {
|
|
assert.strictEqual(stdout, '[]\n');
|
|
assert.strictEqual(stderr, '');
|
|
}));
|
|
});
|
|
|
|
// Assert that module loading works.
|
|
{
|
|
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(code, 42);
|
|
}));
|
|
}
|
|
|
|
// Check that builtin modules are pre-defined.
|
|
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.
|
|
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(
|
|
stdout, 'Loaded as a module, exiting with status code 42.\n');
|
|
assert.strictEqual(stderr, '');
|
|
}));
|
|
|
|
// Missing argument should not crash.
|
|
child.exec(...common.escapePOSIXShell`"${process.execPath}" -e`, common.mustCall((err, stdout, stderr) => {
|
|
assert.strictEqual(err.code, 9);
|
|
assert.strictEqual(stdout, '');
|
|
assert.strictEqual(stderr.trim(),
|
|
`${process.execPath}: -e requires an argument`);
|
|
}));
|
|
|
|
// Empty program should do nothing.
|
|
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(...common.escapePOSIXShell`"${process.execPath}" -p "\\-42"`, common.mustSucceed((stdout, stderr) => {
|
|
assert.strictEqual(stdout, '-42\n');
|
|
assert.strictEqual(stderr, '');
|
|
}));
|
|
|
|
child.exec(...common.escapePOSIXShell`"${process.execPath}" --use-strict -p process.execArgv`,
|
|
common.mustSucceed((stdout, stderr) => {
|
|
assert.strictEqual(
|
|
stdout, "[ '--use-strict', '-p', 'process.execArgv' ]\n"
|
|
);
|
|
assert.strictEqual(stderr, '');
|
|
}));
|
|
|
|
// Regression test for https://github.com/nodejs/node/issues/3574.
|
|
{
|
|
const emptyFile = fixtures.path('empty.js');
|
|
|
|
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.
|
|
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);
|
|
}));
|
|
}
|
|
|
|
// Regression test for https://github.com/nodejs/node/issues/8534.
|
|
{
|
|
const script = `
|
|
// console.log() can revive the event loop so we must be careful
|
|
// to write from a 'beforeExit' event listener only once.
|
|
process.once("beforeExit", () => console.log("beforeExit"));
|
|
process.on("exit", () => console.log("exit"));
|
|
console.log("start");
|
|
`;
|
|
const options = { encoding: 'utf8' };
|
|
const proc = child.spawnSync(process.execPath, ['-e', script], options);
|
|
assert.strictEqual(proc.stderr, '');
|
|
assert.strictEqual(proc.stdout, 'start\nbeforeExit\nexit\n');
|
|
}
|
|
|
|
// Regression test for https://github.com/nodejs/node/issues/11948.
|
|
{
|
|
const script = `
|
|
process.on('message', (message) => {
|
|
if (message === 'ping') process.send('pong');
|
|
if (message === 'exit') process.disconnect();
|
|
});
|
|
`;
|
|
const proc = child.fork('-e', [script]);
|
|
proc.on('exit', common.mustCall((exitCode, signalCode) => {
|
|
assert.strictEqual(exitCode, 0);
|
|
assert.strictEqual(signalCode, null);
|
|
}));
|
|
proc.on('message', (message) => {
|
|
if (message === 'pong') proc.send('exit');
|
|
});
|
|
proc.send('ping');
|
|
}
|
|
|
|
[ '-arg1',
|
|
'-arg1 arg2 --arg3',
|
|
'--',
|
|
'arg1 -- arg2',
|
|
].forEach(function(args) {
|
|
|
|
// Ensure that arguments are successfully passed to eval.
|
|
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.
|
|
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.
|
|
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);
|
|
}));
|
|
});
|
|
|
|
// ESModule eval tests
|
|
|
|
|
|
// Assert that "42\n" is written to stdout on module eval.
|
|
const execOptions = '--input-type module';
|
|
child.exec(
|
|
...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(
|
|
...common.escapePOSIXShell`"${process.execPath}" ${execOptions} --print --eval "42"`,
|
|
common.mustCall((err, stdout, stderr) => {
|
|
assert.ok(err);
|
|
assert.strictEqual(stdout, '');
|
|
assert.ok(stderr.includes('--print cannot be used with ESM input'));
|
|
}));
|
|
|
|
// Assert that error is written to stderr on invalid input.
|
|
child.exec(
|
|
...common.escapePOSIXShell`"${process.execPath}" ${execOptions} --eval "!!!!"`,
|
|
common.mustCall((err, stdout, stderr) => {
|
|
assert.ok(err);
|
|
assert.strictEqual(stdout, '');
|
|
assert.ok(stderr.indexOf('SyntaxError: Unexpected end of input') > 0);
|
|
}));
|
|
|
|
// Assert that require is undefined in ESM support
|
|
child.exec(
|
|
...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(
|
|
...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(
|
|
`${cmd} "import './test/fixtures/es-modules/mjs-file.mjs'"`,
|
|
options,
|
|
common.mustSucceed((stdout) => {
|
|
assert.strictEqual(stdout, '.mjs file\n');
|
|
}));
|
|
|
|
|
|
// Assert that packages can be dynamic imported initial cwd-relative with --eval
|
|
child.exec(
|
|
cmd + ' "process.chdir(\'..\');' +
|
|
'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"',
|
|
options,
|
|
common.mustSucceed((stdout) => {
|
|
assert.strictEqual(stdout, '.mjs file\n');
|
|
}));
|
|
|
|
child.exec(
|
|
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(
|
|
...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(
|
|
...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(
|
|
...common.escapePOSIXShell`"${process.execPath}" -p "crypto=Symbol('test')"`,
|
|
common.mustSucceed((stdout) => {
|
|
assert.match(stdout, /Symbol\(test\)/i);
|
|
}));
|
|
child.exec(
|
|
...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(
|
|
...common.escapePOSIXShell`"${process.execPath}" -e "const crypto = {};console.log('randomBytes', typeof crypto.randomBytes)"`,
|
|
common.mustSucceed((stdout) => {
|
|
assert.match(stdout, /randomBytes\sundefined/);
|
|
}));
|
|
child.exec(
|
|
...common.escapePOSIXShell`"${process.execPath}" -e "let crypto = {};console.log('randomBytes', typeof crypto.randomBytes)"`,
|
|
common.mustSucceed((stdout) => {
|
|
assert.match(stdout, /randomBytes\sundefined/);
|
|
}));
|
|
child.exec(
|
|
...common.escapePOSIXShell`"${process.execPath}" -e "var crypto = {};console.log('randomBytes', typeof crypto.randomBytes)"`,
|
|
common.mustSucceed((stdout) => {
|
|
assert.match(stdout, /randomBytes\sundefined/);
|
|
}));
|
|
child.exec(
|
|
...common.escapePOSIXShell`"${process.execPath}" -p "const crypto = {randomBytes:1};typeof crypto.randomBytes"`,
|
|
common.mustSucceed((stdout) => {
|
|
assert.match(stdout, /^number/);
|
|
}));
|
|
child.exec(
|
|
...common.escapePOSIXShell`"${process.execPath}" -p "let crypto = {randomBytes:1};typeof crypto.randomBytes"`,
|
|
common.mustSucceed((stdout) => {
|
|
assert.match(stdout, /^number/);
|
|
}));
|
|
|
|
// Regression test for https://github.com/nodejs/node/issues/45336
|
|
child.execFile(process.execPath,
|
|
['-p',
|
|
'Object.defineProperty(global, "fs", { configurable: false });' +
|
|
'fs === require("node:fs")'],
|
|
common.mustSucceed((stdout) => {
|
|
assert.match(stdout, /^true/);
|
|
}));
|