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'; 23const common = require('../common'); 24const fixtures = require('../common/fixtures'); 25const tmpdir = require('../common/tmpdir'); 26const assert = require('assert'); 27const net = require('net'); 28const repl = require('repl'); 29const { inspect } = require('util'); 30 31const message = 'Read, Eval, Print Loop'; 32const prompt_unix = 'node via Unix socket> '; 33const prompt_tcp = 'node via TCP socket> '; 34 35// Absolute path to test/fixtures/a.js 36const moduleFilename = fixtures.path('a'); 37 38// Function for REPL to run 39global.invoke_me = function(arg) { 40 return `invoked ${arg}`; 41}; 42 43// Helpers for describing the expected output: 44const kArrow = /^ *\^+ *$/; // Arrow of ^ pointing to syntax error location 45const kSource = Symbol('kSource'); // Placeholder standing for input readback 46 47async function runReplTests(socket, prompt, tests) { 48 let lineBuffer = ''; 49 50 for (const { send, expect } of tests) { 51 // Expect can be a single line or multiple lines 52 const expectedLines = Array.isArray(expect) ? expect : [ expect ]; 53 54 console.error('out:', JSON.stringify(send)); 55 socket.write(`${send}\n`); 56 57 for (let expectedLine of expectedLines) { 58 // Special value: kSource refers to last sent source text 59 if (expectedLine === kSource) 60 expectedLine = send; 61 62 while (!lineBuffer.includes('\n')) { 63 lineBuffer += await event(socket, expect); 64 65 // Cut away the initial prompt 66 while (lineBuffer.startsWith(prompt)) 67 lineBuffer = lineBuffer.substr(prompt.length); 68 69 // Allow to match partial text if no newline was received, because 70 // sending newlines from the REPL itself would be redundant 71 // (e.g. in the `... ` multiline prompt: The user already pressed 72 // enter for that, so the REPL shouldn't do it again!). 73 if (lineBuffer === expectedLine && !expectedLine.includes('\n')) 74 lineBuffer += '\n'; 75 } 76 77 // Split off the current line. 78 const newlineOffset = lineBuffer.indexOf('\n'); 79 let actualLine = lineBuffer.substr(0, newlineOffset); 80 lineBuffer = lineBuffer.substr(newlineOffset + 1); 81 82 // This might have been skipped in the loop above because the buffer 83 // already contained a \n to begin with and the entire loop was skipped. 84 while (actualLine.startsWith(prompt)) 85 actualLine = actualLine.substr(prompt.length); 86 87 console.error('in:', JSON.stringify(actualLine)); 88 89 // Match a string directly, or a RegExp through .test(). 90 if (typeof expectedLine === 'string') { 91 assert.strictEqual(actualLine, expectedLine); 92 } else { 93 assert(expectedLine.test(actualLine), 94 `${actualLine} match ${expectedLine}`); 95 } 96 } 97 } 98 99 const remainder = socket.read(); 100 assert(remainder === '' || remainder === null); 101} 102 103const unixTests = [ 104 { 105 send: '', 106 expect: '' 107 }, 108 { 109 send: 'message', 110 expect: `'${message}'` 111 }, 112 { 113 send: 'invoke_me(987)', 114 expect: '\'invoked 987\'' 115 }, 116 { 117 send: 'a = 12345', 118 expect: '12345' 119 }, 120 { 121 send: '{a:1}', 122 expect: '{ a: 1 }' 123 }, 124]; 125 126const strictModeTests = [ 127 { 128 send: 'ref = 1', 129 expect: [/^Uncaught ReferenceError:\s/] 130 }, 131]; 132 133const errorTests = [ 134 // Uncaught error throws and prints out 135 { 136 send: 'throw new Error(\'test error\');', 137 expect: ['Uncaught Error: test error'] 138 }, 139 { 140 send: "throw { foo: 'bar' };", 141 expect: "Uncaught { foo: 'bar' }" 142 }, 143 // Common syntax error is treated as multiline command 144 { 145 send: 'function test_func() {', 146 expect: '... ' 147 }, 148 // You can recover with the .break command 149 { 150 send: '.break', 151 expect: '' 152 }, 153 // But passing the same string to eval() should throw 154 { 155 send: 'eval("function test_func() {")', 156 expect: [/^Uncaught SyntaxError: /] 157 }, 158 // Can handle multiline template literals 159 { 160 send: '`io.js', 161 expect: '... ' 162 }, 163 // Special REPL commands still available 164 { 165 send: '.break', 166 expect: '' 167 }, 168 // Template expressions 169 { 170 send: '`io.js ${"1.0"', 171 expect: '... ' 172 }, 173 { 174 send: '+ ".2"}`', 175 expect: '\'io.js 1.0.2\'' 176 }, 177 { 178 send: '`io.js ${', 179 expect: '... ' 180 }, 181 { 182 send: '"1.0" + ".2"}`', 183 expect: '\'io.js 1.0.2\'' 184 }, 185 // Dot prefix in multiline commands aren't treated as commands 186 { 187 send: '("a"', 188 expect: '... ' 189 }, 190 { 191 send: '.charAt(0))', 192 expect: '\'a\'' 193 }, 194 // Floating point numbers are not interpreted as REPL commands. 195 { 196 send: '.1234', 197 expect: '0.1234' 198 }, 199 // Floating point expressions are not interpreted as REPL commands 200 { 201 send: '.1+.1', 202 expect: '0.2' 203 }, 204 // Can parse valid JSON 205 { 206 send: 'JSON.parse(\'{"valid": "json"}\');', 207 expect: '{ valid: \'json\' }' 208 }, 209 // Invalid input to JSON.parse error is special case of syntax error, 210 // should throw 211 { 212 send: 'JSON.parse(\'{invalid: \\\'json\\\'}\');', 213 expect: [/^Uncaught SyntaxError: /] 214 }, 215 // End of input to JSON.parse error is special case of syntax error, 216 // should throw 217 { 218 send: 'JSON.parse(\'066\');', 219 expect: [/^Uncaught SyntaxError: /] 220 }, 221 // should throw 222 { 223 send: 'JSON.parse(\'{\');', 224 expect: [/^Uncaught SyntaxError: /] 225 }, 226 // invalid RegExps are a special case of syntax error, 227 // should throw 228 { 229 send: '/(/;', 230 expect: [/^Uncaught SyntaxError: /] 231 }, 232 // invalid RegExp modifiers are a special case of syntax error, 233 // should throw (GH-4012) 234 { 235 send: 'new RegExp("foo", "wrong modifier");', 236 expect: [/^Uncaught SyntaxError: /] 237 }, 238 // Strict mode syntax errors should be caught (GH-5178) 239 { 240 send: '(function() { "use strict"; return 0755; })()', 241 expect: [ 242 kSource, 243 kArrow, 244 '', 245 /^Uncaught SyntaxError: /, 246 ] 247 }, 248 { 249 send: '(function(a, a, b) { "use strict"; return a + b + c; })()', 250 expect: [ 251 kSource, 252 kArrow, 253 '', 254 /^Uncaught SyntaxError: /, 255 ] 256 }, 257 { 258 send: '(function() { "use strict"; with (this) {} })()', 259 expect: [ 260 kSource, 261 kArrow, 262 '', 263 /^Uncaught SyntaxError: /, 264 ] 265 }, 266 { 267 send: '(function() { "use strict"; var x; delete x; })()', 268 expect: [ 269 kSource, 270 kArrow, 271 '', 272 /^Uncaught SyntaxError: /, 273 ] 274 }, 275 { 276 send: '(function() { "use strict"; eval = 17; })()', 277 expect: [ 278 kSource, 279 kArrow, 280 '', 281 /^Uncaught SyntaxError: /, 282 ] 283 }, 284 { 285 send: '(function() { "use strict"; if (true) function f() { } })()', 286 expect: [ 287 kSource, 288 kArrow, 289 '', 290 'Uncaught:', 291 /^SyntaxError: /, 292 ] 293 }, 294 // Named functions can be used: 295 { 296 send: 'function blah() { return 1; }', 297 expect: 'undefined' 298 }, 299 { 300 send: 'blah()', 301 expect: '1' 302 }, 303 // Functions should not evaluate twice (#2773) 304 { 305 send: 'var I = [1,2,3,function() {}]; I.pop()', 306 expect: '[Function (anonymous)]' 307 }, 308 // Multiline object 309 { 310 send: '{ a: ', 311 expect: '... ' 312 }, 313 { 314 send: '1 }', 315 expect: '{ a: 1 }' 316 }, 317 // Multiline string-keyed object (e.g. JSON) 318 { 319 send: '{ "a": ', 320 expect: '... ' 321 }, 322 { 323 send: '1 }', 324 expect: '{ a: 1 }' 325 }, 326 // Multiline class with private member. 327 { 328 send: 'class Foo { #private = true ', 329 expect: '... ' 330 }, 331 // Class field with bigint. 332 { 333 send: 'num = 123456789n', 334 expect: '... ' 335 }, 336 // Static class features. 337 { 338 send: 'static foo = "bar" }', 339 expect: 'undefined' 340 }, 341 // Multiline anonymous function with comment 342 { 343 send: '(function() {', 344 expect: '... ' 345 }, 346 { 347 send: '// blah', 348 expect: '... ' 349 }, 350 { 351 send: 'return 1n;', 352 expect: '... ' 353 }, 354 { 355 send: '})()', 356 expect: '1n' 357 }, 358 // Multiline function call 359 { 360 send: 'function f(){}; f(f(1,', 361 expect: '... ' 362 }, 363 { 364 send: '2)', 365 expect: '... ' 366 }, 367 { 368 send: ')', 369 expect: 'undefined' 370 }, 371 // `npm` prompt error message. 372 { 373 send: 'npm install foobar', 374 expect: [ 375 'npm should be run outside of the Node.js REPL, in your normal shell.', 376 '(Press Ctrl+D to exit.)', 377 ] 378 }, 379 { 380 send: '(function() {\n\nreturn 1;\n})()', 381 expect: '... ... ... 1' 382 }, 383 { 384 send: '{\n\na: 1\n}', 385 expect: '... ... ... { a: 1 }' 386 }, 387 { 388 send: 'url.format("http://google.com")', 389 expect: '\'http://google.com/\'' 390 }, 391 { 392 send: 'var path = 42; path', 393 expect: '42' 394 }, 395 // This makes sure that we don't print `undefined` when we actually print 396 // the error message 397 { 398 send: '.invalid_repl_command', 399 expect: 'Invalid REPL keyword' 400 }, 401 // This makes sure that we don't crash when we use an inherited property as 402 // a REPL command 403 { 404 send: '.toString', 405 expect: 'Invalid REPL keyword' 406 }, 407 // Fail when we are not inside a String and a line continuation is used 408 { 409 send: '[] \\', 410 expect: [ 411 kSource, 412 kArrow, 413 '', 414 /^Uncaught SyntaxError: /, 415 ] 416 }, 417 // Do not fail when a String is created with line continuation 418 { 419 send: '\'the\\\nfourth\\\neye\'', 420 expect: ['... ... \'thefourtheye\''] 421 }, 422 // Don't fail when a partial String is created and line continuation is used 423 // with whitespace characters at the end of the string. We are to ignore it. 424 // This test is to make sure that we properly remove the whitespace 425 // characters at the end of line, unlike the buggy `trimWhitespace` function 426 { 427 send: ' \t .break \t ', 428 expect: '' 429 }, 430 // Multiline strings preserve whitespace characters in them 431 { 432 send: '\'the \\\n fourth\t\t\\\n eye \'', 433 expect: '... ... \'the fourth\\t\\t eye \'' 434 }, 435 // More than one multiline strings also should preserve whitespace chars 436 { 437 send: '\'the \\\n fourth\' + \'\t\t\\\n eye \'', 438 expect: '... ... \'the fourth\\t\\t eye \'' 439 }, 440 // using REPL commands within a string literal should still work 441 { 442 send: '\'\\\n.break', 443 expect: '... ' + prompt_unix 444 }, 445 // Using REPL command "help" within a string literal should still work 446 { 447 send: '\'thefourth\\\n.help\neye\'', 448 expect: [ 449 /\.break/, 450 /\.clear/, 451 /\.exit/, 452 /\.help/, 453 /\.load/, 454 /\.save/, 455 '', 456 'Press Ctrl+C to abort current expression, Ctrl+D to exit the REPL', 457 /'thefourtheye'/, 458 ] 459 }, 460 // Check for wrapped objects. 461 { 462 send: '{ a: 1 }.a', // ({ a: 1 }.a); 463 expect: '1' 464 }, 465 { 466 send: '{ a: 1 }.a;', // { a: 1 }.a; 467 expect: [ 468 kSource, 469 kArrow, 470 '', 471 /^Uncaught SyntaxError: /, 472 ] 473 }, 474 { 475 send: '{ a: 1 }["a"] === 1', // ({ a: 1 }['a'] === 1); 476 expect: 'true' 477 }, 478 { 479 send: '{ a: 1 }["a"] === 1;', // { a: 1 }; ['a'] === 1; 480 expect: 'false' 481 }, 482 // Empty lines in the REPL should be allowed 483 { 484 send: '\n\r\n\r\n', 485 expect: '' 486 }, 487 // Empty lines in the string literals should not affect the string 488 { 489 send: '\'the\\\n\\\nfourtheye\'\n', 490 expect: '... ... \'thefourtheye\'' 491 }, 492 // Regression test for https://github.com/nodejs/node/issues/597 493 { 494 send: '/(.)(.)(.)(.)(.)(.)(.)(.)(.)/.test(\'123456789\')\n', 495 expect: 'true' 496 }, 497 // The following test's result depends on the RegExp's match from the above 498 { 499 send: 'RegExp.$1\nRegExp.$2\nRegExp.$3\nRegExp.$4\nRegExp.$5\n' + 500 'RegExp.$6\nRegExp.$7\nRegExp.$8\nRegExp.$9\n', 501 expect: ['\'1\'', '\'2\'', '\'3\'', '\'4\'', '\'5\'', '\'6\'', 502 '\'7\'', '\'8\'', '\'9\''] 503 }, 504 // Regression tests for https://github.com/nodejs/node/issues/2749 505 { 506 send: 'function x() {\nreturn \'\\n\';\n }', 507 expect: '... ... undefined' 508 }, 509 { 510 send: 'function x() {\nreturn \'\\\\\';\n }', 511 expect: '... ... undefined' 512 }, 513 // Regression tests for https://github.com/nodejs/node/issues/3421 514 { 515 send: 'function x() {\n//\'\n }', 516 expect: '... ... undefined' 517 }, 518 { 519 send: 'function x() {\n//"\n }', 520 expect: '... ... undefined' 521 }, 522 { 523 send: 'function x() {//\'\n }', 524 expect: '... undefined' 525 }, 526 { 527 send: 'function x() {//"\n }', 528 expect: '... undefined' 529 }, 530 { 531 send: 'function x() {\nvar i = "\'";\n }', 532 expect: '... ... undefined' 533 }, 534 { 535 send: 'function x(/*optional*/) {}', 536 expect: 'undefined' 537 }, 538 { 539 send: 'function x(/* // 5 */) {}', 540 expect: 'undefined' 541 }, 542 { 543 send: '// /* 5 */', 544 expect: 'undefined' 545 }, 546 { 547 send: '"//"', 548 expect: '\'//\'' 549 }, 550 { 551 send: '"data /*with*/ comment"', 552 expect: '\'data /*with*/ comment\'' 553 }, 554 { 555 send: 'function x(/*fn\'s optional params*/) {}', 556 expect: 'undefined' 557 }, 558 { 559 send: '/* \'\n"\n\'"\'\n*/', 560 expect: '... ... ... undefined' 561 }, 562 // REPL should get a normal require() function, not one that allows 563 // access to internal modules without the --expose-internals flag. 564 { 565 send: 'require("internal/repl")', 566 expect: [ 567 /^Uncaught Error: Cannot find module 'internal\/repl'/, 568 /^Require stack:/, 569 /^- <repl>/, 570 /^ at .*/, 571 /^ at .*/, 572 /^ at .*/, 573 /^ at .*/, 574 " code: 'MODULE_NOT_FOUND',", 575 " requireStack: [ '<repl>' ]", 576 '}', 577 ] 578 }, 579 // REPL should handle quotes within regexp literal in multiline mode 580 { 581 send: "function x(s) {\nreturn s.replace(/'/,'');\n}", 582 expect: '... ... undefined' 583 }, 584 { 585 send: "function x(s) {\nreturn s.replace(/'/,'');\n}", 586 expect: '... ... undefined' 587 }, 588 { 589 send: 'function x(s) {\nreturn s.replace(/"/,"");\n}', 590 expect: '... ... undefined' 591 }, 592 { 593 send: 'function x(s) {\nreturn s.replace(/.*/,"");\n}', 594 expect: '... ... undefined' 595 }, 596 { 597 send: '{ var x = 4; }', 598 expect: 'undefined' 599 }, 600 // Illegal token is not recoverable outside string literal, RegExp literal, 601 // or block comment. https://github.com/nodejs/node/issues/3611 602 { 603 send: 'a = 3.5e', 604 expect: [ 605 kSource, 606 kArrow, 607 '', 608 /^Uncaught SyntaxError: /, 609 ] 610 }, 611 // Mitigate https://github.com/nodejs/node/issues/548 612 { 613 send: 'function name(){ return "node"; };name()', 614 expect: '\'node\'' 615 }, 616 { 617 send: 'function name(){ return "nodejs"; };name()', 618 expect: '\'nodejs\'' 619 }, 620 // Avoid emitting repl:line-number for SyntaxError 621 { 622 send: 'a = 3.5e', 623 expect: [ 624 kSource, 625 kArrow, 626 '', 627 /^Uncaught SyntaxError: /, 628 ] 629 }, 630 // Avoid emitting stack trace 631 { 632 send: 'a = 3.5e', 633 expect: [ 634 kSource, 635 kArrow, 636 '', 637 /^Uncaught SyntaxError: /, 638 ] 639 }, 640 641 // https://github.com/nodejs/node/issues/9850 642 { 643 send: 'function* foo() {}; foo().next();', 644 expect: '{ value: undefined, done: true }' 645 }, 646 647 { 648 send: 'function *foo() {}; foo().next();', 649 expect: '{ value: undefined, done: true }' 650 }, 651 652 { 653 send: 'function*foo() {}; foo().next();', 654 expect: '{ value: undefined, done: true }' 655 }, 656 657 { 658 send: 'function * foo() {}; foo().next()', 659 expect: '{ value: undefined, done: true }' 660 }, 661 662 // https://github.com/nodejs/node/issues/9300 663 { 664 send: 'function foo() {\nvar bar = 1 / 1; // "/"\n}', 665 expect: '... ... undefined' 666 }, 667 668 { 669 send: '(function() {\nreturn /foo/ / /bar/;\n}())', 670 expect: '... ... NaN' 671 }, 672 673 { 674 send: '(function() {\nif (false) {} /bar"/;\n}())', 675 expect: '... ... undefined' 676 }, 677 678 // https://github.com/nodejs/node/issues/16483 679 { 680 send: 'new Proxy({x:42}, {get(){throw null}});', 681 expect: 'Proxy [ { x: 42 }, { get: [Function: get] } ]' 682 }, 683 { 684 send: 'repl.writer.options.showProxy = false, new Proxy({x:42}, {});', 685 expect: '{ x: 42 }' 686 }, 687 688 // Newline within template string maintains whitespace. 689 { 690 send: '`foo \n`', 691 expect: '... \'foo \\n\'' 692 }, 693 // Whitespace is not evaluated. 694 { 695 send: ' \t \n', 696 expect: 'undefined' 697 }, 698 // Do not parse `...[]` as a REPL keyword 699 { 700 send: '...[]', 701 expect: [ 702 kSource, 703 kArrow, 704 '', 705 /^Uncaught SyntaxError: /, 706 ] 707 }, 708 // Bring back the repl to prompt 709 { 710 send: '.break', 711 expect: '' 712 }, 713 { 714 send: 'console.log("Missing comma in arg list" process.version)', 715 expect: [ 716 kSource, 717 kArrow, 718 '', 719 /^Uncaught SyntaxError: /, 720 ] 721 }, 722 { 723 send: 'x = {\nfield\n{', 724 expect: [ 725 '... ... {', 726 kArrow, 727 '', 728 /^Uncaught SyntaxError: /, 729 ] 730 }, 731 { 732 send: '(2 + 3))', 733 expect: [ 734 kSource, 735 kArrow, 736 '', 737 /^Uncaught SyntaxError: /, 738 ] 739 }, 740 { 741 send: 'if (typeof process === "object"); {', 742 expect: '... ' 743 }, 744 { 745 send: 'console.log("process is defined");', 746 expect: '... ' 747 }, 748 { 749 send: '} else {', 750 expect: [ 751 kSource, 752 kArrow, 753 '', 754 /^Uncaught SyntaxError: /, 755 ] 756 }, 757 { 758 send: 'console', 759 expect: [ 760 'Object [console] {', 761 ' log: [Function: log],', 762 ' warn: [Function: warn],', 763 ' dir: [Function: dir],', 764 ' time: [Function: time],', 765 ' timeEnd: [Function: timeEnd],', 766 ' timeLog: [Function: timeLog],', 767 ' trace: [Function: trace],', 768 ' assert: [Function: assert],', 769 ' clear: [Function: clear],', 770 ' count: [Function: count],', 771 ' countReset: [Function: countReset],', 772 ' group: [Function: group],', 773 ' groupEnd: [Function: groupEnd],', 774 ' table: [Function: table],', 775 / debug: \[Function: (debug|log)],/, 776 / info: \[Function: (info|log)],/, 777 / dirxml: \[Function: (dirxml|log)],/, 778 / error: \[Function: (error|warn)],/, 779 / groupCollapsed: \[Function: (groupCollapsed|group)],/, 780 / Console: \[Function: Console],?/, 781 ...process.features.inspector ? [ 782 ' profile: [Function: profile],', 783 ' profileEnd: [Function: profileEnd],', 784 ' timeStamp: [Function: timeStamp],', 785 ' context: [Function: context]', 786 ] : [], 787 '}', 788 ] 789 }, 790]; 791 792const tcpTests = [ 793 { 794 send: '', 795 expect: '' 796 }, 797 { 798 send: 'invoke_me(333)', 799 expect: '\'invoked 333\'' 800 }, 801 { 802 send: 'a += 1', 803 expect: '12346' 804 }, 805 { 806 send: `require(${JSON.stringify(moduleFilename)}).number`, 807 expect: '42' 808 }, 809 { 810 send: 'import comeOn from \'fhqwhgads\'', 811 expect: [ 812 kSource, 813 kArrow, 814 '', 815 'Uncaught:', 816 /^SyntaxError: .* dynamic import/, 817 ] 818 }, 819]; 820 821(async function() { 822 { 823 const [ socket, replServer ] = await startUnixRepl(); 824 825 await runReplTests(socket, prompt_unix, unixTests); 826 await runReplTests(socket, prompt_unix, errorTests); 827 replServer.replMode = repl.REPL_MODE_STRICT; 828 await runReplTests(socket, prompt_unix, strictModeTests); 829 830 socket.end(); 831 } 832 { 833 const [ socket ] = await startTCPRepl(); 834 835 await runReplTests(socket, prompt_tcp, tcpTests); 836 837 socket.end(); 838 } 839 common.allowGlobals(...Object.values(global)); 840})().then(common.mustCall()); 841 842function startTCPRepl() { 843 let resolveSocket, resolveReplServer; 844 845 const server = net.createServer(common.mustCall((socket) => { 846 assert.strictEqual(server, socket.server); 847 848 socket.on('end', common.mustCall(() => { 849 socket.end(); 850 })); 851 852 resolveReplServer(repl.start(prompt_tcp, socket)); 853 })); 854 855 server.listen(0, common.mustCall(() => { 856 const client = net.createConnection(server.address().port); 857 858 client.setEncoding('utf8'); 859 860 client.on('connect', common.mustCall(() => { 861 assert.strictEqual(client.readable, true); 862 assert.strictEqual(client.writable, true); 863 864 resolveSocket(client); 865 })); 866 867 client.on('close', common.mustCall(() => { 868 server.close(); 869 })); 870 })); 871 872 return Promise.all([ 873 new Promise((resolve) => resolveSocket = resolve), 874 new Promise((resolve) => resolveReplServer = resolve), 875 ]); 876} 877 878function startUnixRepl() { 879 let resolveSocket, resolveReplServer; 880 881 const server = net.createServer(common.mustCall((socket) => { 882 assert.strictEqual(server, socket.server); 883 884 socket.on('end', common.mustCall(() => { 885 socket.end(); 886 })); 887 888 const replServer = repl.start({ 889 prompt: prompt_unix, 890 input: socket, 891 output: socket, 892 useGlobal: true 893 }); 894 replServer.context.message = message; 895 resolveReplServer(replServer); 896 })); 897 898 tmpdir.refresh(); 899 900 server.listen(common.PIPE, common.mustCall(() => { 901 const client = net.createConnection(common.PIPE); 902 903 client.setEncoding('utf8'); 904 905 client.on('connect', common.mustCall(() => { 906 assert.strictEqual(client.readable, true); 907 assert.strictEqual(client.writable, true); 908 909 resolveSocket(client); 910 })); 911 912 client.on('close', common.mustCall(() => { 913 server.close(); 914 })); 915 })); 916 917 return Promise.all([ 918 new Promise((resolve) => resolveSocket = resolve), 919 new Promise((resolve) => resolveReplServer = resolve), 920 ]); 921} 922 923function event(ee, expected) { 924 return new Promise((resolve, reject) => { 925 const timeout = setTimeout(() => { 926 const data = inspect(expected, { compact: false }); 927 const msg = `The REPL did not reply as expected for:\n\n${data}`; 928 reject(new Error(msg)); 929 }, common.platformTimeout(9999)); 930 ee.once('data', common.mustCall((...args) => { 931 clearTimeout(timeout); 932 resolve(...args); 933 })); 934 }); 935} 936