1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23if (module.parent) { 24 // Signal we've been loaded as a module. 25 // The following console.log() is part of the test. 26 console.log('Loaded as a module, exiting with status code 42.'); 27 process.exit(42); 28} 29 30const common = require('../common'); 31const assert = require('assert'); 32const child = require('child_process'); 33const path = require('path'); 34const fixtures = require('../common/fixtures'); 35const nodejs = `"${process.execPath}"`; 36 37if (process.argv.length > 2) { 38 console.log(process.argv.slice(2).join(' ')); 39 process.exit(0); 40} 41 42// Assert that nothing is written to stdout. 43child.exec(`${nodejs} --eval 42`, common.mustCall((err, stdout, stderr) => { 44 assert.ifError(err); 45 assert.strictEqual(stdout, ''); 46 assert.strictEqual(stderr, ''); 47})); 48 49// Assert that "42\n" is written to stderr. 50child.exec(`${nodejs} --eval "console.error(42)"`, 51 common.mustCall((err, stdout, stderr) => { 52 assert.ifError(err); 53 assert.strictEqual(stdout, ''); 54 assert.strictEqual(stderr, '42\n'); 55 })); 56 57// Assert that the expected output is written to stdout. 58['--print', '-p -e', '-pe', '-p'].forEach((s) => { 59 const cmd = `${nodejs} ${s} `; 60 61 child.exec(`${cmd}42`, common.mustCall((err, stdout, stderr) => { 62 assert.ifError(err); 63 assert.strictEqual(stdout, '42\n'); 64 assert.strictEqual(stderr, ''); 65 })); 66 67 child.exec(`${cmd} '[]'`, common.mustCall((err, stdout, stderr) => { 68 assert.ifError(err); 69 assert.strictEqual(stdout, '[]\n'); 70 assert.strictEqual(stderr, ''); 71 })); 72}); 73 74// Assert that module loading works. 75{ 76 // Replace \ by / because Windows uses backslashes in paths, but they're still 77 // interpreted as the escape character when put between quotes. 78 const filename = __filename.replace(/\\/g, '/'); 79 80 child.exec(`${nodejs} --eval "require('${filename}')"`, 81 common.mustCall((err, stdout, stderr) => { 82 assert.strictEqual(err.code, 42); 83 assert.strictEqual( 84 stdout, 'Loaded as a module, exiting with status code 42.\n'); 85 assert.strictEqual(stderr, ''); 86 })); 87} 88 89// Check that builtin modules are pre-defined. 90child.exec(`${nodejs} --print "os.platform()"`, 91 common.mustCall((err, stdout, stderr) => { 92 assert.ifError(err); 93 assert.strictEqual(stderr, ''); 94 assert.strictEqual(stdout.trim(), require('os').platform()); 95 })); 96 97// Module path resolve bug regression test. 98child.exec(`${nodejs} --eval "require('./test/parallel/test-cli-eval.js')"`, 99 { cwd: path.resolve(__dirname, '../../') }, 100 common.mustCall((err, stdout, stderr) => { 101 assert.strictEqual(err.code, 42); 102 assert.strictEqual( 103 stdout, 'Loaded as a module, exiting with status code 42.\n'); 104 assert.strictEqual(stderr, ''); 105 })); 106 107// Missing argument should not crash. 108child.exec(`${nodejs} -e`, common.mustCall((err, stdout, stderr) => { 109 assert.strictEqual(err.code, 9); 110 assert.strictEqual(stdout, ''); 111 assert.strictEqual(stderr.trim(), 112 `${process.execPath}: -e requires an argument`); 113})); 114 115// Empty program should do nothing. 116child.exec(`${nodejs} -e ""`, common.mustCall((err, stdout, stderr) => { 117 assert.ifError(err); 118 assert.strictEqual(stdout, ''); 119 assert.strictEqual(stderr, ''); 120})); 121 122// "\\-42" should be interpreted as an escaped expression, not a switch. 123child.exec(`${nodejs} -p "\\-42"`, common.mustCall((err, stdout, stderr) => { 124 assert.ifError(err); 125 assert.strictEqual(stdout, '-42\n'); 126 assert.strictEqual(stderr, ''); 127})); 128 129child.exec(`${nodejs} --use-strict -p process.execArgv`, 130 common.mustCall((err, stdout, stderr) => { 131 assert.ifError(err); 132 assert.strictEqual( 133 stdout, "[ '--use-strict', '-p', 'process.execArgv' ]\n" 134 ); 135 assert.strictEqual(stderr, ''); 136 })); 137 138// Regression test for https://github.com/nodejs/node/issues/3574. 139{ 140 let emptyFile = fixtures.path('empty.js'); 141 if (common.isWindows) { 142 emptyFile = emptyFile.replace(/\\/g, '\\\\'); 143 } 144 145 child.exec(`${nodejs} -e 'require("child_process").fork("${emptyFile}")'`, 146 common.mustCall((err, stdout, stderr) => { 147 assert.ifError(err); 148 assert.strictEqual(stdout, ''); 149 assert.strictEqual(stderr, ''); 150 })); 151 152 // Make sure that monkey-patching process.execArgv doesn't cause child_process 153 // to incorrectly munge execArgv. 154 child.exec( 155 `${nodejs} -e "process.execArgv = ['-e', 'console.log(42)', 'thirdArg'];` + 156 `require('child_process').fork('${emptyFile}')"`, 157 common.mustCall((err, stdout, stderr) => { 158 assert.ifError(err); 159 assert.strictEqual(stdout, '42\n'); 160 assert.strictEqual(stderr, ''); 161 })); 162} 163 164// Regression test for https://github.com/nodejs/node/issues/8534. 165{ 166 const script = ` 167 // console.log() can revive the event loop so we must be careful 168 // to write from a 'beforeExit' event listener only once. 169 process.once("beforeExit", () => console.log("beforeExit")); 170 process.on("exit", () => console.log("exit")); 171 console.log("start"); 172 `; 173 const options = { encoding: 'utf8' }; 174 const proc = child.spawnSync(process.execPath, ['-e', script], options); 175 assert.strictEqual(proc.stderr, ''); 176 assert.strictEqual(proc.stdout, 'start\nbeforeExit\nexit\n'); 177} 178 179// Regression test for https://github.com/nodejs/node/issues/11948. 180{ 181 const script = ` 182 process.on('message', (message) => { 183 if (message === 'ping') process.send('pong'); 184 if (message === 'exit') process.disconnect(); 185 }); 186 `; 187 const proc = child.fork('-e', [script]); 188 proc.on('exit', common.mustCall((exitCode, signalCode) => { 189 assert.strictEqual(exitCode, 0); 190 assert.strictEqual(signalCode, null); 191 })); 192 proc.on('message', (message) => { 193 if (message === 'pong') proc.send('exit'); 194 }); 195 proc.send('ping'); 196} 197 198[ '-arg1', 199 '-arg1 arg2 --arg3', 200 '--', 201 'arg1 -- arg2', 202].forEach(function(args) { 203 204 // Ensure that arguments are successfully passed to eval. 205 const opt = ' --eval "console.log(process.argv.slice(1).join(\' \'))"'; 206 const cmd = `${nodejs}${opt} -- ${args}`; 207 child.exec(cmd, common.mustCall(function(err, stdout, stderr) { 208 assert.strictEqual(stdout, `${args}\n`); 209 assert.strictEqual(stderr, ''); 210 assert.strictEqual(err, null); 211 })); 212 213 // Ensure that arguments are successfully passed to print. 214 const popt = ' --print "process.argv.slice(1).join(\' \')"'; 215 const pcmd = `${nodejs}${popt} -- ${args}`; 216 child.exec(pcmd, common.mustCall(function(err, stdout, stderr) { 217 assert.strictEqual(stdout, `${args}\n`); 218 assert.strictEqual(stderr, ''); 219 assert.strictEqual(err, null); 220 })); 221 222 // Ensure that arguments are successfully passed to a script. 223 // The first argument after '--' should be interpreted as a script 224 // filename. 225 const filecmd = `${nodejs} -- "${__filename}" ${args}`; 226 child.exec(filecmd, common.mustCall(function(err, stdout, stderr) { 227 assert.strictEqual(stdout, `${args}\n`); 228 assert.strictEqual(stderr, ''); 229 assert.strictEqual(err, null); 230 })); 231}); 232 233// ESModule eval tests 234 235 236// Assert that "42\n" is written to stdout on module eval. 237const execOptions = '--input-type module'; 238child.exec( 239 `${nodejs} ${execOptions} --eval "console.log(42)"`, 240 common.mustCall((err, stdout) => { 241 assert.ifError(err); 242 assert.strictEqual(stdout, '42\n'); 243 })); 244 245// Assert that "42\n" is written to stdout with print option. 246child.exec( 247 `${nodejs} ${execOptions} --print --eval "42"`, 248 common.mustCall((err, stdout) => { 249 assert.ifError(err); 250 assert.strictEqual(stdout, '42\n'); 251 })); 252 253// Assert that error is written to stderr on invalid input. 254child.exec( 255 `${nodejs} ${execOptions} --eval "!!!!"`, 256 common.mustCall((err, stdout, stderr) => { 257 assert.ok(err); 258 assert.strictEqual(stdout, ''); 259 assert.ok(stderr.indexOf('SyntaxError: Unexpected end of input') > 0); 260 })); 261 262// Assert that require is undefined in ESM support 263child.exec( 264 `${nodejs} ${execOptions} --eval "console.log(typeof require);"`, 265 common.mustCall((err, stdout) => { 266 assert.ifError(err); 267 assert.strictEqual(stdout, 'undefined\n'); 268 })); 269 270// Assert that import.meta is defined in ESM 271child.exec( 272 `${nodejs} ${execOptions} --eval "console.log(typeof import.meta);"`, 273 common.mustCall((err, stdout) => { 274 assert.ifError(err); 275 assert.strictEqual(stdout, 'object\n'); 276 })); 277 278// Assert that packages can be imported cwd-relative with --eval 279child.exec( 280 `${nodejs} ${execOptions} ` + 281 '--eval "import \'./test/fixtures/es-modules/mjs-file.mjs\'"', 282 common.mustCall((err, stdout) => { 283 assert.ifError(err); 284 assert.strictEqual(stdout, '.mjs file\n'); 285 })); 286 287 288// Assert that packages can be dynamic imported initial cwd-relative with --eval 289child.exec( 290 `${nodejs} ${execOptions} ` + 291 '--eval "process.chdir(\'..\');' + 292 'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"', 293 common.mustCall((err, stdout) => { 294 assert.ifError(err); 295 assert.strictEqual(stdout, '.mjs file\n'); 296 })); 297 298child.exec( 299 `${nodejs} ${execOptions} ` + 300 '--eval "process.chdir(\'..\');' + 301 'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"', 302 common.mustCall((err, stdout) => { 303 assert.ifError(err); 304 assert.strictEqual(stdout, '.mjs file\n'); 305 })); 306