11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci// Flags: --expose-internals 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciconst common = require('../common'); 61cb0ef41Sopenharmony_ciconst stream = require('stream'); 71cb0ef41Sopenharmony_ciconst REPL = require('internal/repl'); 81cb0ef41Sopenharmony_ciconst assert = require('assert'); 91cb0ef41Sopenharmony_ciconst fs = require('fs'); 101cb0ef41Sopenharmony_ciconst path = require('path'); 111cb0ef41Sopenharmony_ciconst { inspect } = require('util'); 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_cicommon.skipIfDumbTerminal(); 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ciconst tmpdir = require('../common/tmpdir'); 161cb0ef41Sopenharmony_citmpdir.refresh(); 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciprocess.throwDeprecation = true; 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ciconst defaultHistoryPath = path.join(tmpdir.path, '.node_repl_history'); 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci// Create an input stream specialized for testing an array of actions 231cb0ef41Sopenharmony_ciclass ActionStream extends stream.Stream { 241cb0ef41Sopenharmony_ci run(data) { 251cb0ef41Sopenharmony_ci const _iter = data[Symbol.iterator](); 261cb0ef41Sopenharmony_ci const doAction = () => { 271cb0ef41Sopenharmony_ci const next = _iter.next(); 281cb0ef41Sopenharmony_ci if (next.done) { 291cb0ef41Sopenharmony_ci // Close the repl. Note that it must have a clean prompt to do so. 301cb0ef41Sopenharmony_ci this.emit('keypress', '', { ctrl: true, name: 'd' }); 311cb0ef41Sopenharmony_ci return; 321cb0ef41Sopenharmony_ci } 331cb0ef41Sopenharmony_ci const action = next.value; 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci if (typeof action === 'object') { 361cb0ef41Sopenharmony_ci this.emit('keypress', '', action); 371cb0ef41Sopenharmony_ci } else { 381cb0ef41Sopenharmony_ci this.emit('data', `${action}`); 391cb0ef41Sopenharmony_ci } 401cb0ef41Sopenharmony_ci setImmediate(doAction); 411cb0ef41Sopenharmony_ci }; 421cb0ef41Sopenharmony_ci doAction(); 431cb0ef41Sopenharmony_ci } 441cb0ef41Sopenharmony_ci resume() {} 451cb0ef41Sopenharmony_ci pause() {} 461cb0ef41Sopenharmony_ci} 471cb0ef41Sopenharmony_ciActionStream.prototype.readable = true; 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci// Mock keys 501cb0ef41Sopenharmony_ciconst ENTER = { name: 'enter' }; 511cb0ef41Sopenharmony_ciconst UP = { name: 'up' }; 521cb0ef41Sopenharmony_ciconst DOWN = { name: 'down' }; 531cb0ef41Sopenharmony_ciconst LEFT = { name: 'left' }; 541cb0ef41Sopenharmony_ciconst RIGHT = { name: 'right' }; 551cb0ef41Sopenharmony_ciconst BACKSPACE = { name: 'backspace' }; 561cb0ef41Sopenharmony_ciconst TABULATION = { name: 'tab' }; 571cb0ef41Sopenharmony_ciconst WORD_LEFT = { name: 'left', ctrl: true }; 581cb0ef41Sopenharmony_ciconst WORD_RIGHT = { name: 'right', ctrl: true }; 591cb0ef41Sopenharmony_ciconst GO_TO_END = { name: 'end' }; 601cb0ef41Sopenharmony_ciconst SIGINT = { name: 'c', ctrl: true }; 611cb0ef41Sopenharmony_ciconst ESCAPE = { name: 'escape', meta: true }; 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ciconst prompt = '> '; 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ciconst tests = [ 661cb0ef41Sopenharmony_ci { 671cb0ef41Sopenharmony_ci env: { NODE_REPL_HISTORY: defaultHistoryPath }, 681cb0ef41Sopenharmony_ci test: (function*() { 691cb0ef41Sopenharmony_ci // Deleting Array iterator should not break history feature. 701cb0ef41Sopenharmony_ci // 711cb0ef41Sopenharmony_ci // Using a generator function instead of an object to allow the test to 721cb0ef41Sopenharmony_ci // keep iterating even when Array.prototype[Symbol.iterator] has been 731cb0ef41Sopenharmony_ci // deleted. 741cb0ef41Sopenharmony_ci yield 'const ArrayIteratorPrototype ='; 751cb0ef41Sopenharmony_ci yield ' Object.getPrototypeOf(Array.prototype[Symbol.iterator]());'; 761cb0ef41Sopenharmony_ci yield ENTER; 771cb0ef41Sopenharmony_ci yield 'const {next} = ArrayIteratorPrototype;'; 781cb0ef41Sopenharmony_ci yield ENTER; 791cb0ef41Sopenharmony_ci yield 'const realArrayIterator = Array.prototype[Symbol.iterator];'; 801cb0ef41Sopenharmony_ci yield ENTER; 811cb0ef41Sopenharmony_ci yield 'delete Array.prototype[Symbol.iterator];'; 821cb0ef41Sopenharmony_ci yield ENTER; 831cb0ef41Sopenharmony_ci yield 'delete ArrayIteratorPrototype.next;'; 841cb0ef41Sopenharmony_ci yield ENTER; 851cb0ef41Sopenharmony_ci yield UP; 861cb0ef41Sopenharmony_ci yield UP; 871cb0ef41Sopenharmony_ci yield DOWN; 881cb0ef41Sopenharmony_ci yield DOWN; 891cb0ef41Sopenharmony_ci yield 'fu'; 901cb0ef41Sopenharmony_ci yield 'n'; 911cb0ef41Sopenharmony_ci yield RIGHT; 921cb0ef41Sopenharmony_ci yield BACKSPACE; 931cb0ef41Sopenharmony_ci yield LEFT; 941cb0ef41Sopenharmony_ci yield LEFT; 951cb0ef41Sopenharmony_ci yield 'A'; 961cb0ef41Sopenharmony_ci yield BACKSPACE; 971cb0ef41Sopenharmony_ci yield GO_TO_END; 981cb0ef41Sopenharmony_ci yield BACKSPACE; 991cb0ef41Sopenharmony_ci yield WORD_LEFT; 1001cb0ef41Sopenharmony_ci yield WORD_RIGHT; 1011cb0ef41Sopenharmony_ci yield ESCAPE; 1021cb0ef41Sopenharmony_ci yield ENTER; 1031cb0ef41Sopenharmony_ci yield 'require("./'; 1041cb0ef41Sopenharmony_ci yield TABULATION; 1051cb0ef41Sopenharmony_ci yield SIGINT; 1061cb0ef41Sopenharmony_ci yield 'import("./'; 1071cb0ef41Sopenharmony_ci yield TABULATION; 1081cb0ef41Sopenharmony_ci yield SIGINT; 1091cb0ef41Sopenharmony_ci yield 'Array.proto'; 1101cb0ef41Sopenharmony_ci yield RIGHT; 1111cb0ef41Sopenharmony_ci yield '.pu'; 1121cb0ef41Sopenharmony_ci yield ENTER; 1131cb0ef41Sopenharmony_ci yield 'ArrayIteratorPrototype.next = next;'; 1141cb0ef41Sopenharmony_ci yield ENTER; 1151cb0ef41Sopenharmony_ci yield 'Array.prototype[Symbol.iterator] = realArrayIterator;'; 1161cb0ef41Sopenharmony_ci yield ENTER; 1171cb0ef41Sopenharmony_ci })(), 1181cb0ef41Sopenharmony_ci expected: [], 1191cb0ef41Sopenharmony_ci clean: false 1201cb0ef41Sopenharmony_ci }, 1211cb0ef41Sopenharmony_ci]; 1221cb0ef41Sopenharmony_ciconst numtests = tests.length; 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ciconst runTestWrap = common.mustCall(runTest, numtests); 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_cifunction cleanupTmpFile() { 1271cb0ef41Sopenharmony_ci try { 1281cb0ef41Sopenharmony_ci // Write over the file, clearing any history 1291cb0ef41Sopenharmony_ci fs.writeFileSync(defaultHistoryPath, ''); 1301cb0ef41Sopenharmony_ci } catch (err) { 1311cb0ef41Sopenharmony_ci if (err.code === 'ENOENT') return true; 1321cb0ef41Sopenharmony_ci throw err; 1331cb0ef41Sopenharmony_ci } 1341cb0ef41Sopenharmony_ci return true; 1351cb0ef41Sopenharmony_ci} 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_cifunction runTest() { 1381cb0ef41Sopenharmony_ci const opts = tests.shift(); 1391cb0ef41Sopenharmony_ci if (!opts) return; // All done 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci const { expected, skip } = opts; 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci // Test unsupported on platform. 1441cb0ef41Sopenharmony_ci if (skip) { 1451cb0ef41Sopenharmony_ci setImmediate(runTestWrap, true); 1461cb0ef41Sopenharmony_ci return; 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci const lastChunks = []; 1491cb0ef41Sopenharmony_ci let i = 0; 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci REPL.createInternalRepl(opts.env, { 1521cb0ef41Sopenharmony_ci input: new ActionStream(), 1531cb0ef41Sopenharmony_ci output: new stream.Writable({ 1541cb0ef41Sopenharmony_ci write(chunk, _, next) { 1551cb0ef41Sopenharmony_ci const output = chunk.toString(); 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci if (!opts.showEscapeCodes && 1581cb0ef41Sopenharmony_ci (output[0] === '\x1B' || /^[\r\n]+$/.test(output))) { 1591cb0ef41Sopenharmony_ci return next(); 1601cb0ef41Sopenharmony_ci } 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci lastChunks.push(output); 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci if (expected.length && !opts.checkTotal) { 1651cb0ef41Sopenharmony_ci try { 1661cb0ef41Sopenharmony_ci assert.strictEqual(output, expected[i]); 1671cb0ef41Sopenharmony_ci } catch (e) { 1681cb0ef41Sopenharmony_ci console.error(`Failed test # ${numtests - tests.length}`); 1691cb0ef41Sopenharmony_ci console.error('Last outputs: ' + inspect(lastChunks, { 1701cb0ef41Sopenharmony_ci breakLength: 5, colors: true 1711cb0ef41Sopenharmony_ci })); 1721cb0ef41Sopenharmony_ci throw e; 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci // TODO(BridgeAR): Auto close on last chunk! 1751cb0ef41Sopenharmony_ci i++; 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci next(); 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci }), 1811cb0ef41Sopenharmony_ci allowBlockingCompletions: true, 1821cb0ef41Sopenharmony_ci completer: opts.completer, 1831cb0ef41Sopenharmony_ci prompt, 1841cb0ef41Sopenharmony_ci useColors: false, 1851cb0ef41Sopenharmony_ci preview: opts.preview, 1861cb0ef41Sopenharmony_ci terminal: true 1871cb0ef41Sopenharmony_ci }, function(err, repl) { 1881cb0ef41Sopenharmony_ci if (err) { 1891cb0ef41Sopenharmony_ci console.error(`Failed test # ${numtests - tests.length}`); 1901cb0ef41Sopenharmony_ci throw err; 1911cb0ef41Sopenharmony_ci } 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ci repl.once('close', () => { 1941cb0ef41Sopenharmony_ci if (opts.clean) 1951cb0ef41Sopenharmony_ci cleanupTmpFile(); 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci if (opts.checkTotal) { 1981cb0ef41Sopenharmony_ci assert.deepStrictEqual(lastChunks, expected); 1991cb0ef41Sopenharmony_ci } else if (expected.length !== i) { 2001cb0ef41Sopenharmony_ci console.error(tests[numtests - tests.length - 1]); 2011cb0ef41Sopenharmony_ci throw new Error(`Failed test # ${numtests - tests.length}`); 2021cb0ef41Sopenharmony_ci } 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci setImmediate(runTestWrap, true); 2051cb0ef41Sopenharmony_ci }); 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci if (opts.columns) { 2081cb0ef41Sopenharmony_ci Object.defineProperty(repl, 'columns', { 2091cb0ef41Sopenharmony_ci value: opts.columns, 2101cb0ef41Sopenharmony_ci enumerable: true 2111cb0ef41Sopenharmony_ci }); 2121cb0ef41Sopenharmony_ci } 2131cb0ef41Sopenharmony_ci repl.input.run(opts.test); 2141cb0ef41Sopenharmony_ci }); 2151cb0ef41Sopenharmony_ci} 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci// run the tests 2181cb0ef41Sopenharmony_cirunTest(); 219