• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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