11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_cirequire('../common');
41cb0ef41Sopenharmony_ciconst assert = require('assert');
51cb0ef41Sopenharmony_ciconst repl = require('repl');
61cb0ef41Sopenharmony_ciconst stream = require('stream');
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_citestSloppyMode();
91cb0ef41Sopenharmony_citestStrictMode();
101cb0ef41Sopenharmony_citestResetContext();
111cb0ef41Sopenharmony_citestResetContextGlobal();
121cb0ef41Sopenharmony_citestMagicMode();
131cb0ef41Sopenharmony_citestError();
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_cifunction testSloppyMode() {
161cb0ef41Sopenharmony_ci  const r = initRepl(repl.REPL_MODE_SLOPPY);
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci  // Cannot use `let` in sloppy mode
191cb0ef41Sopenharmony_ci  r.write(`_;          // initial value undefined
201cb0ef41Sopenharmony_ci          var x = 10;  // evaluates to undefined
211cb0ef41Sopenharmony_ci          _;           // still undefined
221cb0ef41Sopenharmony_ci          y = 10;      // evaluates to 10
231cb0ef41Sopenharmony_ci          _;           // 10 from last eval
241cb0ef41Sopenharmony_ci          _ = 20;      // explicitly set to 20
251cb0ef41Sopenharmony_ci          _;           // 20 from user input
261cb0ef41Sopenharmony_ci          _ = 30;      // make sure we can set it twice and no prompt
271cb0ef41Sopenharmony_ci          _;           // 30 from user input
281cb0ef41Sopenharmony_ci          y = 40;      // make sure eval doesn't change _
291cb0ef41Sopenharmony_ci          _;           // remains 30 from user input
301cb0ef41Sopenharmony_ci          `);
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci  assertOutput(r.output, [
331cb0ef41Sopenharmony_ci    'undefined',
341cb0ef41Sopenharmony_ci    'undefined',
351cb0ef41Sopenharmony_ci    'undefined',
361cb0ef41Sopenharmony_ci    '10',
371cb0ef41Sopenharmony_ci    '10',
381cb0ef41Sopenharmony_ci    'Expression assignment to _ now disabled.',
391cb0ef41Sopenharmony_ci    '20',
401cb0ef41Sopenharmony_ci    '20',
411cb0ef41Sopenharmony_ci    '30',
421cb0ef41Sopenharmony_ci    '30',
431cb0ef41Sopenharmony_ci    '40',
441cb0ef41Sopenharmony_ci    '30',
451cb0ef41Sopenharmony_ci  ]);
461cb0ef41Sopenharmony_ci}
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cifunction testStrictMode() {
491cb0ef41Sopenharmony_ci  const r = initRepl(repl.REPL_MODE_STRICT);
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  r.write(`_;          // initial value undefined
521cb0ef41Sopenharmony_ci          var x = 10;  // evaluates to undefined
531cb0ef41Sopenharmony_ci          _;           // still undefined
541cb0ef41Sopenharmony_ci          let _ = 20;  // use 'let' only in strict mode - evals to undefined
551cb0ef41Sopenharmony_ci          _;           // 20 from user input
561cb0ef41Sopenharmony_ci          _ = 30;      // make sure we can set it twice and no prompt
571cb0ef41Sopenharmony_ci          _;           // 30 from user input
581cb0ef41Sopenharmony_ci          var y = 40;  // make sure eval doesn't change _
591cb0ef41Sopenharmony_ci          _;           // remains 30 from user input
601cb0ef41Sopenharmony_ci          function f() { let _ = 50; } // undefined
611cb0ef41Sopenharmony_ci          f();         // undefined
621cb0ef41Sopenharmony_ci          _;           // remains 30 from user input
631cb0ef41Sopenharmony_ci          `);
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  assertOutput(r.output, [
661cb0ef41Sopenharmony_ci    'undefined',
671cb0ef41Sopenharmony_ci    'undefined',
681cb0ef41Sopenharmony_ci    'undefined',
691cb0ef41Sopenharmony_ci    'undefined',
701cb0ef41Sopenharmony_ci    '20',
711cb0ef41Sopenharmony_ci    '30',
721cb0ef41Sopenharmony_ci    '30',
731cb0ef41Sopenharmony_ci    'undefined',
741cb0ef41Sopenharmony_ci    '30',
751cb0ef41Sopenharmony_ci    'undefined',
761cb0ef41Sopenharmony_ci    'undefined',
771cb0ef41Sopenharmony_ci    '30',
781cb0ef41Sopenharmony_ci  ]);
791cb0ef41Sopenharmony_ci}
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_cifunction testMagicMode() {
821cb0ef41Sopenharmony_ci  const r = initRepl(repl.REPL_MODE_MAGIC);
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  r.write(`_;          // initial value undefined
851cb0ef41Sopenharmony_ci          x = 10;      //
861cb0ef41Sopenharmony_ci          _;           // last eval - 10
871cb0ef41Sopenharmony_ci          let _ = 20;  // undefined
881cb0ef41Sopenharmony_ci          _;           // 20 from user input
891cb0ef41Sopenharmony_ci          _ = 30;      // make sure we can set it twice and no prompt
901cb0ef41Sopenharmony_ci          _;           // 30 from user input
911cb0ef41Sopenharmony_ci          var y = 40;  // make sure eval doesn't change _
921cb0ef41Sopenharmony_ci          _;           // remains 30 from user input
931cb0ef41Sopenharmony_ci          function f() { let _ = 50; return _; } // undefined
941cb0ef41Sopenharmony_ci          f();         // 50
951cb0ef41Sopenharmony_ci          _;           // remains 30 from user input
961cb0ef41Sopenharmony_ci          `);
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci  assertOutput(r.output, [
991cb0ef41Sopenharmony_ci    'undefined',
1001cb0ef41Sopenharmony_ci    '10',
1011cb0ef41Sopenharmony_ci    '10',
1021cb0ef41Sopenharmony_ci    'undefined',
1031cb0ef41Sopenharmony_ci    '20',
1041cb0ef41Sopenharmony_ci    '30',
1051cb0ef41Sopenharmony_ci    '30',
1061cb0ef41Sopenharmony_ci    'undefined',
1071cb0ef41Sopenharmony_ci    '30',
1081cb0ef41Sopenharmony_ci    'undefined',
1091cb0ef41Sopenharmony_ci    '50',
1101cb0ef41Sopenharmony_ci    '30',
1111cb0ef41Sopenharmony_ci  ]);
1121cb0ef41Sopenharmony_ci}
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_cifunction testResetContext() {
1151cb0ef41Sopenharmony_ci  const r = initRepl(repl.REPL_MODE_SLOPPY);
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  r.write(`_ = 10;     // explicitly set to 10
1181cb0ef41Sopenharmony_ci          _;           // 10 from user input
1191cb0ef41Sopenharmony_ci          .clear       // Clearing context...
1201cb0ef41Sopenharmony_ci          _;           // remains 10
1211cb0ef41Sopenharmony_ci          x = 20;      // but behavior reverts to last eval
1221cb0ef41Sopenharmony_ci          _;           // expect 20
1231cb0ef41Sopenharmony_ci          `);
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  assertOutput(r.output, [
1261cb0ef41Sopenharmony_ci    'Expression assignment to _ now disabled.',
1271cb0ef41Sopenharmony_ci    '10',
1281cb0ef41Sopenharmony_ci    '10',
1291cb0ef41Sopenharmony_ci    'Clearing context...',
1301cb0ef41Sopenharmony_ci    '10',
1311cb0ef41Sopenharmony_ci    '20',
1321cb0ef41Sopenharmony_ci    '20',
1331cb0ef41Sopenharmony_ci  ]);
1341cb0ef41Sopenharmony_ci}
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_cifunction testResetContextGlobal() {
1371cb0ef41Sopenharmony_ci  const r = initRepl(repl.REPL_MODE_STRICT, true);
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  r.write(`_ = 10;     // explicitly set to 10
1401cb0ef41Sopenharmony_ci          _;           // 10 from user input
1411cb0ef41Sopenharmony_ci          .clear       // No output because useGlobal is true
1421cb0ef41Sopenharmony_ci          _;           // remains 10
1431cb0ef41Sopenharmony_ci          `);
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  assertOutput(r.output, [
1461cb0ef41Sopenharmony_ci    'Expression assignment to _ now disabled.',
1471cb0ef41Sopenharmony_ci    '10',
1481cb0ef41Sopenharmony_ci    '10',
1491cb0ef41Sopenharmony_ci    '10',
1501cb0ef41Sopenharmony_ci  ]);
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  // Delete globals leaked by REPL when `useGlobal` is `true`
1531cb0ef41Sopenharmony_ci  delete global.module;
1541cb0ef41Sopenharmony_ci  delete global.require;
1551cb0ef41Sopenharmony_ci}
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_cifunction testError() {
1581cb0ef41Sopenharmony_ci  const r = initRepl(repl.REPL_MODE_STRICT);
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  r.write(`_error;                                // initial value undefined
1611cb0ef41Sopenharmony_ci           throw new Error('foo');                // throws error
1621cb0ef41Sopenharmony_ci           _error;                                // shows error
1631cb0ef41Sopenharmony_ci           fs.readdirSync('/nonexistent?');       // throws error, sync
1641cb0ef41Sopenharmony_ci           _error.code;                           // shows error code
1651cb0ef41Sopenharmony_ci           _error.syscall;                        // shows error syscall
1661cb0ef41Sopenharmony_ci           setImmediate(() => { throw new Error('baz'); }); undefined;
1671cb0ef41Sopenharmony_ci                                                  // throws error, async
1681cb0ef41Sopenharmony_ci           `);
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci  setImmediate(() => {
1711cb0ef41Sopenharmony_ci    const lines = r.output.accum.trim().split('\n');
1721cb0ef41Sopenharmony_ci    const expectedLines = [
1731cb0ef41Sopenharmony_ci      'undefined',
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci      // The error, both from the original throw and the `_error` echo.
1761cb0ef41Sopenharmony_ci      'Uncaught Error: foo',
1771cb0ef41Sopenharmony_ci      '[Error: foo]',
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci      // The sync error, with individual property echoes
1801cb0ef41Sopenharmony_ci      /^Uncaught Error: ENOENT: no such file or directory, scandir '.*nonexistent\?'/,
1811cb0ef41Sopenharmony_ci      /Object\.readdirSync/,
1821cb0ef41Sopenharmony_ci      /^ {2}errno: -(2|4058),$/,
1831cb0ef41Sopenharmony_ci      "  syscall: 'scandir',",
1841cb0ef41Sopenharmony_ci      "  code: 'ENOENT',",
1851cb0ef41Sopenharmony_ci      "  path: '/nonexistent?'",
1861cb0ef41Sopenharmony_ci      '}',
1871cb0ef41Sopenharmony_ci      "'ENOENT'",
1881cb0ef41Sopenharmony_ci      "'scandir'",
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci      // Dummy 'undefined' from the explicit silencer + one from the comment
1911cb0ef41Sopenharmony_ci      'undefined',
1921cb0ef41Sopenharmony_ci      'undefined',
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci      // The message from the original throw
1951cb0ef41Sopenharmony_ci      'Uncaught Error: baz',
1961cb0ef41Sopenharmony_ci    ];
1971cb0ef41Sopenharmony_ci    for (const line of lines) {
1981cb0ef41Sopenharmony_ci      const expected = expectedLines.shift();
1991cb0ef41Sopenharmony_ci      if (typeof expected === 'string')
2001cb0ef41Sopenharmony_ci        assert.strictEqual(line, expected);
2011cb0ef41Sopenharmony_ci      else
2021cb0ef41Sopenharmony_ci        assert.match(line, expected);
2031cb0ef41Sopenharmony_ci    }
2041cb0ef41Sopenharmony_ci    assert.strictEqual(expectedLines.length, 0);
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci    // Reset output, check that '_error' is the asynchronously caught error.
2071cb0ef41Sopenharmony_ci    r.output.accum = '';
2081cb0ef41Sopenharmony_ci    r.write(`_error.message                 // show the message
2091cb0ef41Sopenharmony_ci             _error = 0;                    // disable auto-assignment
2101cb0ef41Sopenharmony_ci             throw new Error('quux');       // new error
2111cb0ef41Sopenharmony_ci             _error;                        // should not see the new error
2121cb0ef41Sopenharmony_ci             `);
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci    assertOutput(r.output, [
2151cb0ef41Sopenharmony_ci      "'baz'",
2161cb0ef41Sopenharmony_ci      'Expression assignment to _error now disabled.',
2171cb0ef41Sopenharmony_ci      '0',
2181cb0ef41Sopenharmony_ci      'Uncaught Error: quux',
2191cb0ef41Sopenharmony_ci      '0',
2201cb0ef41Sopenharmony_ci    ]);
2211cb0ef41Sopenharmony_ci  });
2221cb0ef41Sopenharmony_ci}
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_cifunction initRepl(mode, useGlobal) {
2251cb0ef41Sopenharmony_ci  const inputStream = new stream.PassThrough();
2261cb0ef41Sopenharmony_ci  const outputStream = new stream.PassThrough();
2271cb0ef41Sopenharmony_ci  outputStream.accum = '';
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci  outputStream.on('data', (data) => {
2301cb0ef41Sopenharmony_ci    outputStream.accum += data;
2311cb0ef41Sopenharmony_ci  });
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  return repl.start({
2341cb0ef41Sopenharmony_ci    input: inputStream,
2351cb0ef41Sopenharmony_ci    output: outputStream,
2361cb0ef41Sopenharmony_ci    useColors: false,
2371cb0ef41Sopenharmony_ci    terminal: false,
2381cb0ef41Sopenharmony_ci    prompt: '',
2391cb0ef41Sopenharmony_ci    replMode: mode,
2401cb0ef41Sopenharmony_ci    useGlobal: useGlobal
2411cb0ef41Sopenharmony_ci  });
2421cb0ef41Sopenharmony_ci}
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_cifunction assertOutput(output, expected) {
2451cb0ef41Sopenharmony_ci  const lines = output.accum.trim().split('\n');
2461cb0ef41Sopenharmony_ci  assert.deepStrictEqual(lines, expected);
2471cb0ef41Sopenharmony_ci}
248