• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Flags: --expose-internals
2'use strict';
3const common = require('../common');
4const assert = require('assert');
5const cp = require('child_process');
6const internalCp = require('internal/child_process');
7const oldSpawnSync = internalCp.spawnSync;
8
9// Verify that a shell is, in fact, executed
10const doesNotExist = cp.spawnSync('does-not-exist', { shell: true });
11
12assert.notStrictEqual(doesNotExist.file, 'does-not-exist');
13assert.strictEqual(doesNotExist.error, undefined);
14assert.strictEqual(doesNotExist.signal, null);
15
16if (common.isWindows)
17  assert.strictEqual(doesNotExist.status, 1);    // Exit code of cmd.exe
18else
19  assert.strictEqual(doesNotExist.status, 127);  // Exit code of /bin/sh
20
21// Verify that passing arguments works
22internalCp.spawnSync = common.mustCall(function(opts) {
23  assert.strictEqual(opts.args[opts.args.length - 1].replace(/"/g, ''),
24                     'echo foo');
25  return oldSpawnSync(opts);
26});
27const echo = cp.spawnSync('echo', ['foo'], { shell: true });
28internalCp.spawnSync = oldSpawnSync;
29
30assert.strictEqual(echo.stdout.toString().trim(), 'foo');
31
32// Verify that shell features can be used
33const cmd = 'echo bar | cat';
34const command = cp.spawnSync(cmd, { shell: true });
35
36assert.strictEqual(command.stdout.toString().trim(), 'bar');
37
38// Verify that the environment is properly inherited
39const env = cp.spawnSync(`"${process.execPath}" -pe process.env.BAZ`, {
40  env: { ...process.env, BAZ: 'buzz' },
41  shell: true
42});
43
44assert.strictEqual(env.stdout.toString().trim(), 'buzz');
45
46// Verify that the shell internals work properly across platforms.
47{
48  const originalComspec = process.env.comspec;
49
50  // Enable monkey patching process.platform.
51  const originalPlatform = process.platform;
52  let platform = null;
53  Object.defineProperty(process, 'platform', { get: () => platform });
54
55  function test(testPlatform, shell, shellOutput) {
56    platform = testPlatform;
57    const isCmd = /^(?:.*\\)?cmd(?:\.exe)?$/i.test(shellOutput);
58    const cmd = 'not_a_real_command';
59
60    const shellFlags = isCmd ? ['/d', '/s', '/c'] : ['-c'];
61    const outputCmd = isCmd ? `"${cmd}"` : cmd;
62    const windowsVerbatim = isCmd ? true : undefined;
63    internalCp.spawnSync = common.mustCall(function(opts) {
64      assert.strictEqual(opts.file, shellOutput);
65      assert.deepStrictEqual(opts.args,
66                             [shellOutput, ...shellFlags, outputCmd]);
67      assert.strictEqual(opts.shell, shell);
68      assert.strictEqual(opts.file, opts.file);
69      assert.deepStrictEqual(opts.args, opts.args);
70      assert.strictEqual(opts.windowsHide, false);
71      assert.strictEqual(opts.windowsVerbatimArguments,
72                         !!windowsVerbatim);
73    });
74    cp.spawnSync(cmd, { shell });
75    internalCp.spawnSync = oldSpawnSync;
76  }
77
78  // Test Unix platforms with the default shell.
79  test('darwin', true, '/bin/sh');
80
81  // Test Unix platforms with a user specified shell.
82  test('darwin', '/bin/csh', '/bin/csh');
83
84  // Test Android platforms.
85  test('android', true, '/system/bin/sh');
86
87  // Test Windows platforms with a user specified shell.
88  test('win32', 'powershell.exe', 'powershell.exe');
89
90  // Test Windows platforms with the default shell and no comspec.
91  delete process.env.comspec;
92  test('win32', true, 'cmd.exe');
93
94  // Test Windows platforms with the default shell and a comspec value.
95  process.env.comspec = 'powershell.exe';
96  test('win32', true, process.env.comspec);
97
98  // Restore the original value of process.platform.
99  platform = originalPlatform;
100
101  // Restore the original comspec environment variable if necessary.
102  if (originalComspec)
103    process.env.comspec = originalComspec;
104}
105