summaryrefslogtreecommitdiff
path: root/deps/node/deps/node-inspect/test/cli
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2019-04-03 15:43:32 +0200
committerFlorian Dold <florian.dold@gmail.com>2019-04-03 15:45:57 +0200
commit71e285b94c7edaa43aa8115965cf5a36b8e0f80a (patch)
tree7d4aa9d0d5aff686b106cd5da72ba77960c4af43 /deps/node/deps/node-inspect/test/cli
parent7dadf9356b4f3f4137ce982ea5bb960283116e9a (diff)
downloadakono-71e285b94c7edaa43aa8115965cf5a36b8e0f80a.tar.gz
akono-71e285b94c7edaa43aa8115965cf5a36b8e0f80a.tar.bz2
akono-71e285b94c7edaa43aa8115965cf5a36b8e0f80a.zip
Node.js v11.13.0
Diffstat (limited to 'deps/node/deps/node-inspect/test/cli')
-rw-r--r--deps/node/deps/node-inspect/test/cli/backtrace.test.js30
-rw-r--r--deps/node/deps/node-inspect/test/cli/break.test.js195
-rw-r--r--deps/node/deps/node-inspect/test/cli/exceptions.test.js68
-rw-r--r--deps/node/deps/node-inspect/test/cli/exec.test.js77
-rw-r--r--deps/node/deps/node-inspect/test/cli/heap-profiler.test.js34
-rw-r--r--deps/node/deps/node-inspect/test/cli/help.test.js22
-rw-r--r--deps/node/deps/node-inspect/test/cli/invalid-args.test.js54
-rw-r--r--deps/node/deps/node-inspect/test/cli/launch.test.js176
-rw-r--r--deps/node/deps/node-inspect/test/cli/low-level.test.js34
-rw-r--r--deps/node/deps/node-inspect/test/cli/pid.test.js52
-rw-r--r--deps/node/deps/node-inspect/test/cli/preserve-breaks.test.js64
-rw-r--r--deps/node/deps/node-inspect/test/cli/profile.test.js32
-rw-r--r--deps/node/deps/node-inspect/test/cli/scripts.test.js43
-rw-r--r--deps/node/deps/node-inspect/test/cli/start-cli.js156
-rw-r--r--deps/node/deps/node-inspect/test/cli/use-strict.test.js27
-rw-r--r--deps/node/deps/node-inspect/test/cli/watchers.test.js42
16 files changed, 1106 insertions, 0 deletions
diff --git a/deps/node/deps/node-inspect/test/cli/backtrace.test.js b/deps/node/deps/node-inspect/test/cli/backtrace.test.js
new file mode 100644
index 00000000..127ea56b
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/backtrace.test.js
@@ -0,0 +1,30 @@
+'use strict';
+const Path = require('path');
+
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('display and navigate backtrace', (t) => {
+ const script = Path.join('examples', 'backtrace.js');
+ const cli = startCLI([script]);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.stepCommand('c'))
+ .then(() => cli.command('bt'))
+ .then(() => {
+ t.match(cli.output, `#0 topFn ${script}:7:2`);
+ })
+ .then(() => cli.command('backtrace'))
+ .then(() => {
+ t.match(cli.output, `#0 topFn ${script}:7:2`);
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/break.test.js b/deps/node/deps/node-inspect/test/cli/break.test.js
new file mode 100644
index 00000000..ce8c8d6d
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/break.test.js
@@ -0,0 +1,195 @@
+'use strict';
+const Path = require('path');
+
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('stepping through breakpoints', (t) => {
+ const script = Path.join('examples', 'break.js');
+ const cli = startCLI([script]);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:1`,
+ 'pauses in the first line of the script');
+ t.match(
+ cli.output,
+ /> 1 \(function \([^)]+\) \{ const x = 10;/,
+ 'shows the source and marks the current line');
+ })
+ .then(() => cli.stepCommand('n'))
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:2`,
+ 'pauses in next line of the script');
+ t.match(
+ cli.output,
+ '> 2 let name = \'World\';',
+ 'marks the 2nd line');
+ })
+ .then(() => cli.stepCommand('next'))
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:3`,
+ 'pauses in next line of the script');
+ t.match(
+ cli.output,
+ '> 3 name = \'Robin\';',
+ 'marks the 3nd line');
+ })
+ .then(() => cli.stepCommand('cont'))
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:10`,
+ 'pauses on the next breakpoint');
+ t.match(
+ cli.output,
+ '>10 debugger;',
+ 'marks the debugger line');
+ })
+
+ // Prepare additional breakpoints
+ .then(() => cli.command('sb("break.js", 6)'))
+ .then(() => t.notMatch(cli.output, 'Could not resolve breakpoint'))
+ .then(() => cli.command('sb("otherFunction()")'))
+ .then(() => cli.command('sb(16)'))
+ .then(() => t.notMatch(cli.output, 'Could not resolve breakpoint'))
+ .then(() => cli.command('breakpoints'))
+ .then(() => {
+ t.match(cli.output, `#0 ${script}:6`);
+ t.match(cli.output, `#1 ${script}:16`);
+ })
+
+ .then(() => cli.command('list()'))
+ .then(() => {
+ t.match(cli.output, '>10 debugger;', 'prints and marks current line');
+ t.strictDeepEqual(
+ cli.parseSourceLines(),
+ [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+ 'prints 5 lines before and after');
+ })
+ .then(() => cli.command('list(2)'))
+ .then(() => {
+ t.match(cli.output, '>10 debugger;', 'prints and marks current line');
+ t.strictDeepEqual(
+ cli.parseSourceLines(),
+ [8, 9, 10, 11, 12],
+ 'prints 2 lines before and after');
+ })
+
+ .then(() => cli.stepCommand('s'))
+ .then(() => cli.stepCommand(''))
+ .then(() => {
+ t.match(
+ cli.output,
+ 'break in timers.js',
+ 'entered timers.js');
+ })
+ .then(() => cli.stepCommand('cont'))
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:16`,
+ 'found breakpoint we set above w/ line number only');
+ })
+ .then(() => cli.stepCommand('cont'))
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:6`,
+ 'found breakpoint we set above w/ line number & script');
+ })
+ .then(() => cli.stepCommand(''))
+ .then(() => {
+ t.match(
+ cli.output,
+ `debugCommand in ${script}:14`,
+ 'found function breakpoint we set above');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
+
+test('sb before loading file', (t) => {
+ const script = Path.join('examples', 'cjs', 'index.js');
+ const otherScript = Path.join('examples', 'cjs', 'other.js');
+ const cli = startCLI([script]);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('sb("other.js", 2)'))
+ .then(() => {
+ t.match(
+ cli.output,
+ 'not loaded yet',
+ 'warns that the script was not loaded yet');
+ })
+ .then(() => cli.stepCommand('cont'))
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${otherScript}:2`,
+ 'found breakpoint in file that was not loaded yet');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
+
+test('clearBreakpoint', (t) => {
+ const script = Path.join('examples', 'break.js');
+ const cli = startCLI([script]);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('sb("break.js", 3)'))
+ .then(() => cli.command('sb("break.js", 9)'))
+ .then(() => cli.command('breakpoints'))
+ .then(() => {
+ t.match(cli.output, `#0 ${script}:3`);
+ t.match(cli.output, `#1 ${script}:9`);
+ })
+ .then(() => cli.command('clearBreakpoint("break.js", 4)'))
+ .then(() => {
+ t.match(cli.output, 'Could not find breakpoint');
+ })
+ .then(() => cli.command('clearBreakpoint("not-such-script.js", 3)'))
+ .then(() => {
+ t.match(cli.output, 'Could not find breakpoint');
+ })
+ .then(() => cli.command('clearBreakpoint("break.js", 3)'))
+ .then(() => cli.command('breakpoints'))
+ .then(() => {
+ t.match(cli.output, `#0 ${script}:9`);
+ })
+ .then(() => cli.stepCommand('cont'))
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:9`,
+ 'hits the 2nd breakpoint because the 1st was cleared');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/exceptions.test.js b/deps/node/deps/node-inspect/test/cli/exceptions.test.js
new file mode 100644
index 00000000..18b7f185
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/exceptions.test.js
@@ -0,0 +1,68 @@
+'use strict';
+const Path = require('path');
+
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('break on (uncaught) exceptions', (t) => {
+ const script = Path.join('examples', 'exceptions.js');
+ const cli = startCLI([script]);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(cli.output, `break in ${script}:1`);
+ })
+ // making sure it will die by default:
+ .then(() => cli.command('c'))
+ // TODO: Remove FATAL ERROR once node doesn't show a FATAL ERROR anymore
+ .then(() => cli.waitFor(/disconnect|FATAL ERROR/))
+
+ // Next run: With `breakOnException` it pauses in both places
+ .then(() => cli.stepCommand('r'))
+ .then(() => cli.waitForInitialBreak())
+ .then(() => {
+ t.match(cli.output, `break in ${script}:1`);
+ })
+ .then(() => cli.command('breakOnException'))
+ .then(() => cli.stepCommand('c'))
+ .then(() => {
+ t.match(cli.output, `exception in ${script}:3`);
+ })
+ .then(() => cli.stepCommand('c'))
+ .then(() => {
+ t.match(cli.output, `exception in ${script}:9`);
+ })
+
+ // Next run: With `breakOnUncaught` it only pauses on the 2nd exception
+ .then(() => cli.command('breakOnUncaught'))
+ .then(() => cli.stepCommand('r')) // also, the setting survives the restart
+ .then(() => cli.waitForInitialBreak())
+ .then(() => {
+ t.match(cli.output, `break in ${script}:1`);
+ })
+ .then(() => cli.stepCommand('c'))
+ .then(() => {
+ t.match(cli.output, `exception in ${script}:9`);
+ })
+
+ // Next run: Back to the initial state! It should die again.
+ .then(() => cli.command('breakOnNone'))
+ .then(() => cli.stepCommand('r'))
+ .then(() => cli.waitForInitialBreak())
+ .then(() => {
+ t.match(cli.output, `break in ${script}:1`);
+ })
+ .then(() => cli.command('c'))
+ // TODO: Remove FATAL ERROR once node doesn't show a FATAL ERROR anymore
+ .then(() => cli.waitFor(/disconnect|FATAL ERROR/))
+
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/exec.test.js b/deps/node/deps/node-inspect/test/cli/exec.test.js
new file mode 100644
index 00000000..acfd6e34
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/exec.test.js
@@ -0,0 +1,77 @@
+'use strict';
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('examples/alive.js', (t) => {
+ const cli = startCLI(['examples/alive.js']);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('exec [typeof heartbeat, typeof process.exit]'))
+ .then(() => {
+ t.match(cli.output, '[ \'function\', \'function\' ]', 'works w/o paren');
+ })
+ .then(() => cli.command('repl'))
+ .then(() => {
+ t.match(
+ cli.output,
+ 'Press Ctrl + C to leave debug repl\n> ',
+ 'shows hint for how to leave repl');
+ t.notMatch(cli.output, 'debug>', 'changes the repl style');
+ })
+ .then(() => cli.command('[typeof heartbeat, typeof process.exit]'))
+ .then(() => cli.waitFor(/function/))
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(
+ cli.output,
+ '[ \'function\', \'function\' ]', 'can evaluate in the repl');
+ t.match(cli.output, /> $/);
+ })
+ .then(() => cli.ctrlC())
+ .then(() => cli.waitFor(/debug> $/))
+ .then(() => cli.command('exec("[typeof heartbeat, typeof process.exit]")'))
+ .then(() => {
+ t.match(cli.output, '[ \'function\', \'function\' ]', 'works w/ paren');
+ })
+ .then(() => cli.command('cont'))
+ .then(() => cli.command('exec [typeof heartbeat, typeof process.exit]'))
+ .then(() => {
+ t.match(
+ cli.output,
+ '[ \'undefined\', \'function\' ]',
+ 'non-paused exec can see global but not module-scope values');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
+
+test('exec .scope', (t) => {
+ const cli = startCLI(['examples/backtrace.js']);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.stepCommand('c'))
+ .then(() => cli.command('exec .scope'))
+ .then(() => {
+ t.match(
+ cli.output,
+ '\'moduleScoped\'', 'displays closure from module body');
+ t.match(cli.output, '\'a\'', 'displays local / function arg');
+ t.match(cli.output, '\'l1\'', 'displays local scope');
+ t.notMatch(cli.output, '\'encodeURIComponent\'', 'omits global scope');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/heap-profiler.test.js b/deps/node/deps/node-inspect/test/cli/heap-profiler.test.js
new file mode 100644
index 00000000..ebd734e0
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/heap-profiler.test.js
@@ -0,0 +1,34 @@
+'use strict';
+const { test } = require('tap');
+const { readFileSync, unlinkSync } = require('fs');
+
+const startCLI = require('./start-cli');
+const filename = 'node.heapsnapshot';
+
+function cleanup() {
+ try {
+ unlinkSync(filename);
+ } catch (_) {
+ // Ignore.
+ }
+}
+
+cleanup();
+
+test('Heap profiler take snapshot', (t) => {
+ const cli = startCLI(['examples/empty.js']);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ // Check that the snapshot is valid JSON.
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('takeHeapSnapshot()'))
+ .then(() => JSON.parse(readFileSync(filename, 'utf8')))
+ .then(() => cleanup())
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/help.test.js b/deps/node/deps/node-inspect/test/cli/help.test.js
new file mode 100644
index 00000000..9f0c081b
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/help.test.js
@@ -0,0 +1,22 @@
+'use strict';
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('examples/empty.js', (t) => {
+ const cli = startCLI(['examples/empty.js']);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('help'))
+ .then(() => {
+ t.match(cli.output, /run, restart, r\s+/m);
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/invalid-args.test.js b/deps/node/deps/node-inspect/test/cli/invalid-args.test.js
new file mode 100644
index 00000000..c1aaeb6a
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/invalid-args.test.js
@@ -0,0 +1,54 @@
+'use strict';
+const Path = require('path');
+const { createServer } = require('net');
+
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('launch CLI w/o args', (t) => {
+ const cli = startCLI([]);
+ return cli.quit()
+ .then((code) => {
+ t.equal(code, 1, 'exits with non-zero exit code');
+ t.match(cli.output, /^Usage:/, 'Prints usage info');
+ });
+});
+
+test('launch w/ invalid host:port', (t) => {
+ const cli = startCLI(['localhost:914']);
+ return cli.quit()
+ .then((code) => {
+ t.match(
+ cli.output,
+ 'failed to connect',
+ 'Tells the user that the connection failed');
+ t.equal(code, 1, 'exits with non-zero exit code');
+ });
+});
+
+test('launch w/ unavailable port', async (t) => {
+ const blocker = createServer((socket) => socket.end());
+ const port = await new Promise((resolve, reject) => {
+ blocker.on('error', reject);
+ blocker.listen(0, '127.0.0.1', () => resolve(blocker.address().port));
+ });
+
+ try {
+ const script = Path.join('examples', 'three-lines.js');
+ const cli = startCLI([`--port=${port}`, script]);
+ const code = await cli.quit();
+
+ t.notMatch(
+ cli.output,
+ 'report this bug',
+ 'Omits message about reporting this as a bug');
+ t.match(
+ cli.output,
+ `waiting for 127.0.0.1:${port} to be free`,
+ 'Tells the user that the port wasn\'t available');
+ t.equal(code, 1, 'exits with non-zero exit code');
+ } finally {
+ blocker.close();
+ }
+});
diff --git a/deps/node/deps/node-inspect/test/cli/launch.test.js b/deps/node/deps/node-inspect/test/cli/launch.test.js
new file mode 100644
index 00000000..8808d47a
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/launch.test.js
@@ -0,0 +1,176 @@
+'use strict';
+const Path = require('path');
+
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('custom port', (t) => {
+ const CUSTOM_PORT = '9230';
+ const script = Path.join('examples', 'three-lines.js');
+
+ const cli = startCLI([`--port=${CUSTOM_PORT}`, script]);
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(cli.output, 'debug>', 'prints a prompt');
+ t.match(
+ cli.output,
+ new RegExp(`< Debugger listening on [^\n]*${CUSTOM_PORT}`),
+ 'forwards child output');
+ })
+ .then(() => cli.quit())
+ .then((code) => {
+ t.equal(code, 0, 'exits with success');
+ });
+});
+
+test('random port', (t) => {
+ const script = Path.join('examples', 'three-lines.js');
+
+ const cli = startCLI(['--port=0', script]);
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(cli.output, 'debug>', 'prints a prompt');
+ t.match(
+ cli.output,
+ /< Debugger listening on /,
+ 'forwards child output');
+ })
+ .then(() => cli.quit())
+ .then((code) => {
+ t.equal(code, 0, 'exits with success');
+ });
+});
+
+test('random port with --inspect-port=0', (t) => {
+ const script = Path.join('examples', 'three-lines.js');
+
+ const cli = startCLI([script], ['--inspect-port=0']);
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(cli.output, 'debug>', 'prints a prompt');
+ t.match(
+ cli.output,
+ /< Debugger listening on /,
+ 'forwards child output');
+ })
+ .then(() => cli.quit())
+ .then((code) => {
+ t.equal(code, 0, 'exits with success');
+ });
+});
+
+test('examples/three-lines.js', (t) => {
+ const script = Path.join('examples', 'three-lines.js');
+ const cli = startCLI([script]);
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(cli.output, 'debug>', 'prints a prompt');
+ t.match(
+ cli.output,
+ /< Debugger listening on [^\n]*9229/,
+ 'forwards child output');
+ })
+ .then(() => cli.command('["hello", "world"].join(" ")'))
+ .then(() => {
+ t.match(cli.output, 'hello world', 'prints the result');
+ })
+ .then(() => cli.command(''))
+ .then(() => {
+ t.match(cli.output, 'hello world', 'repeats the last command on <enter>');
+ })
+ .then(() => cli.command('version'))
+ .then(() => {
+ t.match(cli.output, process.versions.v8, 'version prints the v8 version');
+ })
+ .then(() => cli.quit())
+ .then((code) => {
+ t.equal(code, 0, 'exits with success');
+ });
+});
+
+test('run after quit / restart', (t) => {
+ const script = Path.join('examples', 'three-lines.js');
+ const cli = startCLI([script]);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.stepCommand('n'))
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:2`,
+ 'steps to the 2nd line');
+ })
+ .then(() => cli.command('cont'))
+ .then(() => cli.waitFor(/disconnect/))
+ .then(() => {
+ t.match(
+ cli.output,
+ 'Waiting for the debugger to disconnect',
+ 'the child was done');
+ })
+ .then(() => {
+ // On windows the socket won't close by itself
+ return cli.command('kill');
+ })
+ .then(() => cli.command('cont'))
+ .then(() => cli.waitFor(/start the app/))
+ .then(() => {
+ t.match(cli.output, 'Use `run` to start the app again');
+ })
+ .then(() => cli.stepCommand('run'))
+ .then(() => cli.waitForInitialBreak())
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:1`,
+ 'is back at the beginning');
+ })
+ .then(() => cli.stepCommand('n'))
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:2`,
+ 'steps to the 2nd line');
+ })
+ .then(() => cli.stepCommand('restart'))
+ .then(() => cli.waitForInitialBreak())
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:1`,
+ 'is back at the beginning');
+ })
+ .then(() => cli.command('kill'))
+ .then(() => cli.command('cont'))
+ .then(() => cli.waitFor(/start the app/))
+ .then(() => {
+ t.match(cli.output, 'Use `run` to start the app again');
+ })
+ .then(() => cli.stepCommand('run'))
+ .then(() => cli.waitForInitialBreak())
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(
+ cli.output,
+ `break in ${script}:1`,
+ 'is back at the beginning');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/low-level.test.js b/deps/node/deps/node-inspect/test/cli/low-level.test.js
new file mode 100644
index 00000000..77e3fc2b
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/low-level.test.js
@@ -0,0 +1,34 @@
+'use strict';
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('Debugger agent direct access', (t) => {
+ const cli = startCLI(['examples/three-lines.js']);
+ const scriptPattern = /^\* (\d+): examples(?:\/|\\)three-lines.js/;
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('scripts'))
+ .then(() => {
+ const [, scriptId] = cli.output.match(scriptPattern);
+ return cli.command(
+ `Debugger.getScriptSource({ scriptId: '${scriptId}' })`
+ );
+ })
+ .then(() => {
+ t.match(
+ cli.output,
+ /scriptSource: '\(function \(/);
+ t.match(
+ cli.output,
+ /let x = 1;/);
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/pid.test.js b/deps/node/deps/node-inspect/test/cli/pid.test.js
new file mode 100644
index 00000000..15d7fdea
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/pid.test.js
@@ -0,0 +1,52 @@
+'use strict';
+const { spawn } = require('child_process');
+const Path = require('path');
+
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+function launchTarget(...args) {
+ const childProc = spawn(process.execPath, args);
+ return Promise.resolve(childProc);
+}
+
+// process.debugPort is our proxy for "the version of node used to run this
+// test suite doesn't support SIGUSR1 for enabling --inspect for a process".
+const defaultsToOldProtocol = process.debugPort === 5858;
+
+test('examples/alive.js', { skip: defaultsToOldProtocol }, (t) => {
+ const script = Path.join('examples', 'alive.js');
+ let cli = null;
+ let target = null;
+
+ function cleanup(error) {
+ if (cli) {
+ cli.quit();
+ cli = null;
+ }
+ if (target) {
+ target.kill();
+ target = null;
+ }
+ if (error) throw error;
+ }
+
+ return launchTarget(script)
+ .then((childProc) => {
+ target = childProc;
+ cli = startCLI(['-p', `${target.pid}`]);
+ return cli.waitForPrompt();
+ })
+ .then(() => cli.command('sb("alive.js", 3)'))
+ .then(() => cli.waitFor(/break/))
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(
+ cli.output,
+ '> 3 ++x;',
+ 'marks the 3rd line');
+ })
+ .then(() => cleanup())
+ .then(null, cleanup);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/preserve-breaks.test.js b/deps/node/deps/node-inspect/test/cli/preserve-breaks.test.js
new file mode 100644
index 00000000..94f61408
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/preserve-breaks.test.js
@@ -0,0 +1,64 @@
+'use strict';
+const Path = require('path');
+
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('run after quit / restart', (t) => {
+ const script = Path.join('examples', 'three-lines.js');
+ const cli = startCLI([script]);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('breakpoints'))
+ .then(() => {
+ t.match(cli.output, 'No breakpoints yet');
+ })
+ .then(() => cli.command('sb(2)'))
+ .then(() => cli.command('sb(3)'))
+ .then(() => cli.command('breakpoints'))
+ .then(() => {
+ t.match(cli.output, `#0 ${script}:2`);
+ t.match(cli.output, `#1 ${script}:3`);
+ })
+ .then(() => cli.stepCommand('c')) // hit line 2
+ .then(() => cli.stepCommand('c')) // hit line 3
+ .then(() => {
+ t.match(cli.output, `break in ${script}:3`);
+ })
+ .then(() => cli.command('restart'))
+ .then(() => cli.waitForInitialBreak())
+ .then(() => {
+ t.match(cli.output, `break in ${script}:1`);
+ })
+ .then(() => cli.stepCommand('c'))
+ .then(() => {
+ t.match(cli.output, `break in ${script}:2`);
+ })
+ .then(() => cli.stepCommand('c'))
+ .then(() => {
+ t.match(cli.output, `break in ${script}:3`);
+ })
+ .then(() => cli.command('breakpoints'))
+ .then(() => {
+ if (process.platform === 'aix') {
+ // TODO: There is a known issue on AIX where the breakpoints aren't
+ // properly resolved yet when we reach this point.
+ // Eventually that should be figured out but for now we don't want
+ // to fail builds because of it.
+ t.match(cli.output, /#0 [^\n]+three-lines\.js\$?:2/);
+ t.match(cli.output, /#1 [^\n]+three-lines\.js\$?:3/);
+ } else {
+ t.match(cli.output, `#0 ${script}:2`);
+ t.match(cli.output, `#1 ${script}:3`);
+ }
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/profile.test.js b/deps/node/deps/node-inspect/test/cli/profile.test.js
new file mode 100644
index 00000000..0f900c5a
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/profile.test.js
@@ -0,0 +1,32 @@
+'use strict';
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+function delay(ms) {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
+test('profiles', (t) => {
+ const cli = startCLI(['examples/empty.js']);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('exec console.profile()'))
+ .then(() => {
+ t.match(cli.output, 'undefined');
+ })
+ .then(() => cli.command('exec console.profileEnd()'))
+ .then(() => delay(250))
+ .then(() => {
+ t.match(cli.output, 'undefined');
+ t.match(cli.output, 'Captured new CPU profile.');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/scripts.test.js b/deps/node/deps/node-inspect/test/cli/scripts.test.js
new file mode 100644
index 00000000..1546b804
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/scripts.test.js
@@ -0,0 +1,43 @@
+'use strict';
+const Path = require('path');
+
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('list scripts', (t) => {
+ const script = Path.join('examples', 'three-lines.js');
+ const cli = startCLI([script]);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('scripts'))
+ .then(() => {
+ t.match(
+ cli.output,
+ /^\* \d+: examples(?:\/|\\)three-lines\.js/,
+ 'lists the user script');
+ t.notMatch(
+ cli.output,
+ /\d+: module\.js <native>/,
+ 'omits node-internal scripts');
+ })
+ .then(() => cli.command('scripts(true)'))
+ .then(() => {
+ t.match(
+ cli.output,
+ /\* \d+: examples(?:\/|\\)three-lines\.js/,
+ 'lists the user script');
+ t.match(
+ cli.output,
+ /\d+: module\.js <native>/,
+ 'includes node-internal scripts');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/start-cli.js b/deps/node/deps/node-inspect/test/cli/start-cli.js
new file mode 100644
index 00000000..b086dcd8
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/start-cli.js
@@ -0,0 +1,156 @@
+'use strict';
+const spawn = require('child_process').spawn;
+
+// This allows us to keep the helper inside of `test/` without tap warning
+// about "pending" test files.
+const tap = require('tap');
+tap.test('startCLI', (t) => t.end());
+
+const CLI =
+ process.env.USE_EMBEDDED_NODE_INSPECT === '1' ?
+ 'inspect' :
+ require.resolve('../../cli.js');
+
+const BREAK_MESSAGE = new RegExp('(?:' + [
+ 'assert', 'break', 'break on start', 'debugCommand',
+ 'exception', 'other', 'promiseRejection',
+].join('|') + ') in', 'i');
+
+function startCLI(args, flags = []) {
+ const child = spawn(process.execPath, [...flags, CLI, ...args]);
+ let isFirstStdoutChunk = true;
+
+ const outputBuffer = [];
+ function bufferOutput(chunk) {
+ if (isFirstStdoutChunk) {
+ isFirstStdoutChunk = false;
+ outputBuffer.push(chunk.replace(/^debug>\s*/, ''));
+ } else {
+ outputBuffer.push(chunk);
+ }
+ }
+
+ function getOutput() {
+ return outputBuffer.join('').toString()
+ .replace(/^[^\n]*?[\b]/mg, '');
+ }
+
+ child.stdout.setEncoding('utf8');
+ child.stdout.on('data', bufferOutput);
+ child.stderr.setEncoding('utf8');
+ child.stderr.on('data', bufferOutput);
+
+ if (process.env.VERBOSE === '1') {
+ child.stdout.pipe(process.stderr);
+ child.stderr.pipe(process.stderr);
+ }
+
+ return {
+ flushOutput() {
+ const output = this.output;
+ outputBuffer.length = 0;
+ return output;
+ },
+
+ waitFor(pattern, timeout = 2000) {
+ function checkPattern(str) {
+ if (Array.isArray(pattern)) {
+ return pattern.every((p) => p.test(str));
+ }
+ return pattern.test(str);
+ }
+
+ return new Promise((resolve, reject) => {
+ function checkOutput() {
+ if (checkPattern(getOutput())) {
+ tearDown(); // eslint-disable-line no-use-before-define
+ resolve();
+ }
+ }
+
+ function onChildExit() {
+ tearDown(); // eslint-disable-line no-use-before-define
+ reject(new Error(
+ `Child quit while waiting for ${pattern}; found: ${this.output}`));
+ }
+
+ const timer = setTimeout(() => {
+ tearDown(); // eslint-disable-line no-use-before-define
+ reject(new Error([
+ `Timeout (${timeout}) while waiting for ${pattern}`,
+ `found: ${this.output}`,
+ ].join('; ')));
+ }, timeout);
+
+ function tearDown() {
+ clearTimeout(timer);
+ child.stdout.removeListener('data', checkOutput);
+ child.removeListener('exit', onChildExit);
+ }
+
+ child.on('exit', onChildExit);
+ child.stdout.on('data', checkOutput);
+ checkOutput();
+ });
+ },
+
+ waitForPrompt(timeout = 2000) {
+ return this.waitFor(/>\s+$/, timeout);
+ },
+
+ waitForInitialBreak(timeout = 2000) {
+ return this.waitFor(/break (?:on start )?in/i, timeout)
+ .then(() => {
+ if (/Break on start/.test(this.output)) {
+ return this.command('next', false)
+ .then(() => this.waitFor(/break in/, timeout));
+ }
+ });
+ },
+
+ ctrlC() {
+ return this.command('.interrupt');
+ },
+
+ get output() {
+ return getOutput();
+ },
+
+ get rawOutput() {
+ return outputBuffer.join('').toString();
+ },
+
+ parseSourceLines() {
+ return getOutput().split('\n')
+ .map((line) => line.match(/(?:\*|>)?\s*(\d+)/))
+ .filter((match) => match !== null)
+ .map((match) => +match[1]);
+ },
+
+ command(input, flush = true) {
+ if (flush) {
+ this.flushOutput();
+ }
+ child.stdin.write(input);
+ child.stdin.write('\n');
+ return this.waitForPrompt();
+ },
+
+ stepCommand(input) {
+ this.flushOutput();
+ child.stdin.write(input);
+ child.stdin.write('\n');
+ return this
+ .waitFor(BREAK_MESSAGE)
+ .then(() => this.waitForPrompt());
+ },
+
+ quit() {
+ return new Promise((resolve) => {
+ child.stdin.end();
+ child.on('exit', resolve);
+ });
+ },
+ };
+}
+module.exports = startCLI;
diff --git a/deps/node/deps/node-inspect/test/cli/use-strict.test.js b/deps/node/deps/node-inspect/test/cli/use-strict.test.js
new file mode 100644
index 00000000..780802a5
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/use-strict.test.js
@@ -0,0 +1,27 @@
+'use strict';
+const Path = require('path');
+
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('for whiles that starts with strict directive', (t) => {
+ const script = Path.join('examples', 'use-strict.js');
+ const cli = startCLI([script]);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => {
+ t.match(
+ cli.output,
+ /break in [^:]+:(?:1|2)[^\d]/,
+ 'pauses either on strict directive or first "real" line');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});
diff --git a/deps/node/deps/node-inspect/test/cli/watchers.test.js b/deps/node/deps/node-inspect/test/cli/watchers.test.js
new file mode 100644
index 00000000..46bcde19
--- /dev/null
+++ b/deps/node/deps/node-inspect/test/cli/watchers.test.js
@@ -0,0 +1,42 @@
+'use strict';
+const { test } = require('tap');
+
+const startCLI = require('./start-cli');
+
+test('stepping through breakpoints', (t) => {
+ const cli = startCLI(['examples/break.js']);
+
+ function onFatal(error) {
+ cli.quit();
+ throw error;
+ }
+
+ return cli.waitForInitialBreak()
+ .then(() => cli.waitForPrompt())
+ .then(() => cli.command('watch("x")'))
+ .then(() => cli.command('watch("\\"Hello\\"")'))
+ .then(() => cli.command('watch("42")'))
+ .then(() => cli.command('watch("NaN")'))
+ .then(() => cli.command('watch("true")'))
+ .then(() => cli.command('watch("[1, 2]")'))
+ .then(() => cli.command('watch("process.env")'))
+ .then(() => cli.command('watchers'))
+ .then(() => {
+ t.match(cli.output, 'x is not defined');
+ })
+ .then(() => cli.command('unwatch("42")'))
+ .then(() => cli.stepCommand('n'))
+ .then(() => {
+ t.match(cli.output, '0: x = 10');
+ t.match(cli.output, '1: "Hello" = \'Hello\'');
+ t.match(cli.output, '2: NaN = NaN');
+ t.match(cli.output, '3: true = true');
+ t.match(cli.output, '4: [1, 2] = [ 1, 2 ]');
+ t.match(
+ cli.output,
+ /5: process\.env =\n\s+\{[\s\S]+,\n\s+\.\.\. \}/,
+ 'shows "..." for process.env');
+ })
+ .then(() => cli.quit())
+ .then(null, onFatal);
+});