11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci// Flags: --expose-internals 231cb0ef41Sopenharmony_ci'use strict'; 241cb0ef41Sopenharmony_ciconst common = require('../common'); 251cb0ef41Sopenharmony_cicommon.skipIfDumbTerminal(); 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ciconst assert = require('assert'); 281cb0ef41Sopenharmony_ciconst readline = require('readline'); 291cb0ef41Sopenharmony_ciconst util = require('util'); 301cb0ef41Sopenharmony_ciconst { 311cb0ef41Sopenharmony_ci getStringWidth, 321cb0ef41Sopenharmony_ci stripVTControlCharacters 331cb0ef41Sopenharmony_ci} = require('internal/util/inspect'); 341cb0ef41Sopenharmony_ciconst { EventEmitter, getEventListeners } = require('events'); 351cb0ef41Sopenharmony_ciconst { Writable, Readable } = require('stream'); 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciclass FakeInput extends EventEmitter { 381cb0ef41Sopenharmony_ci resume() {} 391cb0ef41Sopenharmony_ci pause() {} 401cb0ef41Sopenharmony_ci write() {} 411cb0ef41Sopenharmony_ci end() {} 421cb0ef41Sopenharmony_ci} 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_cifunction isWarned(emitter) { 451cb0ef41Sopenharmony_ci for (const name in emitter) { 461cb0ef41Sopenharmony_ci const listeners = emitter[name]; 471cb0ef41Sopenharmony_ci if (listeners.warned) return true; 481cb0ef41Sopenharmony_ci } 491cb0ef41Sopenharmony_ci return false; 501cb0ef41Sopenharmony_ci} 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_cifunction getInterface(options) { 531cb0ef41Sopenharmony_ci const fi = new FakeInput(); 541cb0ef41Sopenharmony_ci const rli = new readline.Interface({ 551cb0ef41Sopenharmony_ci input: fi, 561cb0ef41Sopenharmony_ci output: fi, 571cb0ef41Sopenharmony_ci ...options, 581cb0ef41Sopenharmony_ci }); 591cb0ef41Sopenharmony_ci return [rli, fi]; 601cb0ef41Sopenharmony_ci} 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_cifunction assertCursorRowsAndCols(rli, rows, cols) { 631cb0ef41Sopenharmony_ci const cursorPos = rli.getCursorPos(); 641cb0ef41Sopenharmony_ci assert.strictEqual(cursorPos.rows, rows); 651cb0ef41Sopenharmony_ci assert.strictEqual(cursorPos.cols, cols); 661cb0ef41Sopenharmony_ci} 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci{ 691cb0ef41Sopenharmony_ci const input = new FakeInput(); 701cb0ef41Sopenharmony_ci const rl = readline.Interface({ input }); 711cb0ef41Sopenharmony_ci assert(rl instanceof readline.Interface); 721cb0ef41Sopenharmony_ci} 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci{ 751cb0ef41Sopenharmony_ci const fi = new FakeInput(); 761cb0ef41Sopenharmony_ci const rli = new readline.Interface( 771cb0ef41Sopenharmony_ci fi, 781cb0ef41Sopenharmony_ci fi, 791cb0ef41Sopenharmony_ci common.mustCall((line) => [[], line]), 801cb0ef41Sopenharmony_ci true, 811cb0ef41Sopenharmony_ci ); 821cb0ef41Sopenharmony_ci assert(rli instanceof readline.Interface); 831cb0ef41Sopenharmony_ci fi.emit('data', 'a\t'); 841cb0ef41Sopenharmony_ci rli.close(); 851cb0ef41Sopenharmony_ci} 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci[ 881cb0ef41Sopenharmony_ci undefined, 891cb0ef41Sopenharmony_ci 50, 901cb0ef41Sopenharmony_ci 0, 911cb0ef41Sopenharmony_ci 100.5, 921cb0ef41Sopenharmony_ci 5000, 931cb0ef41Sopenharmony_ci].forEach((crlfDelay) => { 941cb0ef41Sopenharmony_ci const [rli] = getInterface({ crlfDelay }); 951cb0ef41Sopenharmony_ci assert.strictEqual(rli.crlfDelay, Math.max(crlfDelay || 100, 100)); 961cb0ef41Sopenharmony_ci rli.close(); 971cb0ef41Sopenharmony_ci}); 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci{ 1001cb0ef41Sopenharmony_ci const input = new FakeInput(); 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci // Constructor throws if completer is not a function or undefined 1031cb0ef41Sopenharmony_ci ['not an array', 123, 123n, {}, true, Symbol(), null].forEach((invalid) => { 1041cb0ef41Sopenharmony_ci assert.throws(() => { 1051cb0ef41Sopenharmony_ci readline.createInterface({ 1061cb0ef41Sopenharmony_ci input, 1071cb0ef41Sopenharmony_ci completer: invalid 1081cb0ef41Sopenharmony_ci }); 1091cb0ef41Sopenharmony_ci }, { 1101cb0ef41Sopenharmony_ci name: 'TypeError', 1111cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_VALUE' 1121cb0ef41Sopenharmony_ci }); 1131cb0ef41Sopenharmony_ci }); 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci // Constructor throws if history is not an array 1161cb0ef41Sopenharmony_ci ['not an array', 123, 123n, {}, true, Symbol(), null].forEach((history) => { 1171cb0ef41Sopenharmony_ci assert.throws(() => { 1181cb0ef41Sopenharmony_ci readline.createInterface({ 1191cb0ef41Sopenharmony_ci input, 1201cb0ef41Sopenharmony_ci history, 1211cb0ef41Sopenharmony_ci }); 1221cb0ef41Sopenharmony_ci }, { 1231cb0ef41Sopenharmony_ci name: 'TypeError', 1241cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_TYPE' 1251cb0ef41Sopenharmony_ci }); 1261cb0ef41Sopenharmony_ci }); 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci // Constructor throws if historySize is not a positive number 1291cb0ef41Sopenharmony_ci ['not a number', -1, NaN, {}, true, Symbol(), null].forEach((historySize) => { 1301cb0ef41Sopenharmony_ci assert.throws(() => { 1311cb0ef41Sopenharmony_ci readline.createInterface({ 1321cb0ef41Sopenharmony_ci input, 1331cb0ef41Sopenharmony_ci historySize, 1341cb0ef41Sopenharmony_ci }); 1351cb0ef41Sopenharmony_ci }, { 1361cb0ef41Sopenharmony_ci name: 'RangeError', 1371cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_VALUE' 1381cb0ef41Sopenharmony_ci }); 1391cb0ef41Sopenharmony_ci }); 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci // Check for invalid tab sizes. 1421cb0ef41Sopenharmony_ci assert.throws( 1431cb0ef41Sopenharmony_ci () => new readline.Interface({ 1441cb0ef41Sopenharmony_ci input, 1451cb0ef41Sopenharmony_ci tabSize: 0 1461cb0ef41Sopenharmony_ci }), 1471cb0ef41Sopenharmony_ci { code: 'ERR_OUT_OF_RANGE' } 1481cb0ef41Sopenharmony_ci ); 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci assert.throws( 1511cb0ef41Sopenharmony_ci () => new readline.Interface({ 1521cb0ef41Sopenharmony_ci input, 1531cb0ef41Sopenharmony_ci tabSize: '4' 1541cb0ef41Sopenharmony_ci }), 1551cb0ef41Sopenharmony_ci { code: 'ERR_INVALID_ARG_TYPE' } 1561cb0ef41Sopenharmony_ci ); 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci assert.throws( 1591cb0ef41Sopenharmony_ci () => new readline.Interface({ 1601cb0ef41Sopenharmony_ci input, 1611cb0ef41Sopenharmony_ci tabSize: 4.5 1621cb0ef41Sopenharmony_ci }), 1631cb0ef41Sopenharmony_ci { 1641cb0ef41Sopenharmony_ci code: 'ERR_OUT_OF_RANGE', 1651cb0ef41Sopenharmony_ci message: 'The value of "tabSize" is out of range. ' + 1661cb0ef41Sopenharmony_ci 'It must be an integer. Received 4.5' 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci ); 1691cb0ef41Sopenharmony_ci} 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_ci// Sending a single character with no newline 1721cb0ef41Sopenharmony_ci{ 1731cb0ef41Sopenharmony_ci const fi = new FakeInput(); 1741cb0ef41Sopenharmony_ci const rli = new readline.Interface(fi, {}); 1751cb0ef41Sopenharmony_ci rli.on('line', common.mustNotCall()); 1761cb0ef41Sopenharmony_ci fi.emit('data', 'a'); 1771cb0ef41Sopenharmony_ci rli.close(); 1781cb0ef41Sopenharmony_ci} 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci// Sending multiple newlines at once that does not end with a new line and a 1811cb0ef41Sopenharmony_ci// `end` event(last line is). \r should behave like \n when alone. 1821cb0ef41Sopenharmony_ci{ 1831cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 1841cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 1851cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 1861cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 1871cb0ef41Sopenharmony_ci }, expectedLines.length - 1)); 1881cb0ef41Sopenharmony_ci fi.emit('data', expectedLines.join('\r')); 1891cb0ef41Sopenharmony_ci rli.close(); 1901cb0ef41Sopenharmony_ci} 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci// \r at start of input should output blank line 1931cb0ef41Sopenharmony_ci{ 1941cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 1951cb0ef41Sopenharmony_ci const expectedLines = ['', 'foo' ]; 1961cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 1971cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 1981cb0ef41Sopenharmony_ci }, expectedLines.length)); 1991cb0ef41Sopenharmony_ci fi.emit('data', '\rfoo\r'); 2001cb0ef41Sopenharmony_ci rli.close(); 2011cb0ef41Sopenharmony_ci} 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci// \t does not become part of the input when there is a completer function 2041cb0ef41Sopenharmony_ci{ 2051cb0ef41Sopenharmony_ci const completer = (line) => [[], line]; 2061cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, completer }); 2071cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 2081cb0ef41Sopenharmony_ci assert.strictEqual(line, 'foo'); 2091cb0ef41Sopenharmony_ci })); 2101cb0ef41Sopenharmony_ci for (const character of '\tfo\to\t') { 2111cb0ef41Sopenharmony_ci fi.emit('data', character); 2121cb0ef41Sopenharmony_ci } 2131cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 2141cb0ef41Sopenharmony_ci rli.close(); 2151cb0ef41Sopenharmony_ci} 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci// \t when there is no completer function should behave like an ordinary 2181cb0ef41Sopenharmony_ci// character 2191cb0ef41Sopenharmony_ci{ 2201cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 2211cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 2221cb0ef41Sopenharmony_ci assert.strictEqual(line, '\t'); 2231cb0ef41Sopenharmony_ci })); 2241cb0ef41Sopenharmony_ci fi.emit('data', '\t'); 2251cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 2261cb0ef41Sopenharmony_ci rli.close(); 2271cb0ef41Sopenharmony_ci} 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci// Adding history lines should emit the history event with 2301cb0ef41Sopenharmony_ci// the history array 2311cb0ef41Sopenharmony_ci{ 2321cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 2331cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 2341cb0ef41Sopenharmony_ci rli.on('history', common.mustCall((history) => { 2351cb0ef41Sopenharmony_ci const expectedHistory = expectedLines.slice(0, history.length).reverse(); 2361cb0ef41Sopenharmony_ci assert.deepStrictEqual(history, expectedHistory); 2371cb0ef41Sopenharmony_ci }, expectedLines.length)); 2381cb0ef41Sopenharmony_ci for (const line of expectedLines) { 2391cb0ef41Sopenharmony_ci fi.emit('data', `${line}\n`); 2401cb0ef41Sopenharmony_ci } 2411cb0ef41Sopenharmony_ci rli.close(); 2421cb0ef41Sopenharmony_ci} 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci// Altering the history array in the listener should not alter 2451cb0ef41Sopenharmony_ci// the line being processed 2461cb0ef41Sopenharmony_ci{ 2471cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 2481cb0ef41Sopenharmony_ci const expectedLine = 'foo'; 2491cb0ef41Sopenharmony_ci rli.on('history', common.mustCall((history) => { 2501cb0ef41Sopenharmony_ci assert.strictEqual(history[0], expectedLine); 2511cb0ef41Sopenharmony_ci history.shift(); 2521cb0ef41Sopenharmony_ci })); 2531cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 2541cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLine); 2551cb0ef41Sopenharmony_ci assert.strictEqual(rli.history.length, 0); 2561cb0ef41Sopenharmony_ci })); 2571cb0ef41Sopenharmony_ci fi.emit('data', `${expectedLine}\n`); 2581cb0ef41Sopenharmony_ci rli.close(); 2591cb0ef41Sopenharmony_ci} 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_ci// Duplicate lines are removed from history when 2621cb0ef41Sopenharmony_ci// `options.removeHistoryDuplicates` is `true` 2631cb0ef41Sopenharmony_ci{ 2641cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ 2651cb0ef41Sopenharmony_ci terminal: true, 2661cb0ef41Sopenharmony_ci removeHistoryDuplicates: true 2671cb0ef41Sopenharmony_ci }); 2681cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat']; 2691cb0ef41Sopenharmony_ci // ['foo', 'baz', 'bar', bat']; 2701cb0ef41Sopenharmony_ci let callCount = 0; 2711cb0ef41Sopenharmony_ci rli.on('line', (line) => { 2721cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines[callCount]); 2731cb0ef41Sopenharmony_ci callCount++; 2741cb0ef41Sopenharmony_ci }); 2751cb0ef41Sopenharmony_ci fi.emit('data', `${expectedLines.join('\n')}\n`); 2761cb0ef41Sopenharmony_ci assert.strictEqual(callCount, expectedLines.length); 2771cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bat' 2781cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 2791cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bar' 2801cb0ef41Sopenharmony_ci assert.notStrictEqual(rli.line, expectedLines[--callCount]); 2811cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 2821cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'baz' 2831cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 2841cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'foo' 2851cb0ef41Sopenharmony_ci assert.notStrictEqual(rli.line, expectedLines[--callCount]); 2861cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 2871cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 0); 2881cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'down' }); // 'baz' 2891cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'baz'); 2901cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 2); 2911cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'n', ctrl: true }); // 'bar' 2921cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bar'); 2931cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 1); 2941cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'n', ctrl: true }); 2951cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bat'); 2961cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 0); 2971cb0ef41Sopenharmony_ci // Activate the substring history search. 2981cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'down' }); // 'bat' 2991cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bat'); 3001cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 3011cb0ef41Sopenharmony_ci // Deactivate substring history search. 3021cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'backspace' }); // 'ba' 3031cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 3041cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 3051cb0ef41Sopenharmony_ci // Activate the substring history search. 3061cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'down' }); // 'ba' 3071cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 3081cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 3091cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'down' }); // 'ba' 3101cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 3111cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 3121cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bat' 3131cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 0); 3141cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bat'); 3151cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bar' 3161cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 1); 3171cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bar'); 3181cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'baz' 3191cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 2); 3201cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'baz'); 3211cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'ba' 3221cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 4); 3231cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 3241cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'ba' 3251cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 4); 3261cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 3271cb0ef41Sopenharmony_ci // Deactivate substring history search and reset history index. 3281cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'right' }); // 'ba' 3291cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 3301cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 3311cb0ef41Sopenharmony_ci // Substring history search activated. 3321cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'ba' 3331cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 0); 3341cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bat'); 3351cb0ef41Sopenharmony_ci rli.close(); 3361cb0ef41Sopenharmony_ci} 3371cb0ef41Sopenharmony_ci 3381cb0ef41Sopenharmony_ci// Duplicate lines are not removed from history when 3391cb0ef41Sopenharmony_ci// `options.removeHistoryDuplicates` is `false` 3401cb0ef41Sopenharmony_ci{ 3411cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ 3421cb0ef41Sopenharmony_ci terminal: true, 3431cb0ef41Sopenharmony_ci removeHistoryDuplicates: false 3441cb0ef41Sopenharmony_ci }); 3451cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat']; 3461cb0ef41Sopenharmony_ci let callCount = 0; 3471cb0ef41Sopenharmony_ci rli.on('line', (line) => { 3481cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines[callCount]); 3491cb0ef41Sopenharmony_ci callCount++; 3501cb0ef41Sopenharmony_ci }); 3511cb0ef41Sopenharmony_ci fi.emit('data', `${expectedLines.join('\n')}\n`); 3521cb0ef41Sopenharmony_ci assert.strictEqual(callCount, expectedLines.length); 3531cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bat' 3541cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3551cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bar' 3561cb0ef41Sopenharmony_ci assert.notStrictEqual(rli.line, expectedLines[--callCount]); 3571cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3581cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'baz' 3591cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3601cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bar' 3611cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3621cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'foo' 3631cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3641cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 0); 3651cb0ef41Sopenharmony_ci rli.close(); 3661cb0ef41Sopenharmony_ci} 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_ci// Regression test for repl freeze, #1968: 3691cb0ef41Sopenharmony_ci// check that nothing fails if 'keypress' event throws. 3701cb0ef41Sopenharmony_ci{ 3711cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 3721cb0ef41Sopenharmony_ci const keys = []; 3731cb0ef41Sopenharmony_ci const err = new Error('bad thing happened'); 3741cb0ef41Sopenharmony_ci fi.on('keypress', (key) => { 3751cb0ef41Sopenharmony_ci keys.push(key); 3761cb0ef41Sopenharmony_ci if (key === 'X') { 3771cb0ef41Sopenharmony_ci throw err; 3781cb0ef41Sopenharmony_ci } 3791cb0ef41Sopenharmony_ci }); 3801cb0ef41Sopenharmony_ci assert.throws( 3811cb0ef41Sopenharmony_ci () => fi.emit('data', 'fooX'), 3821cb0ef41Sopenharmony_ci (e) => { 3831cb0ef41Sopenharmony_ci assert.strictEqual(e, err); 3841cb0ef41Sopenharmony_ci return true; 3851cb0ef41Sopenharmony_ci } 3861cb0ef41Sopenharmony_ci ); 3871cb0ef41Sopenharmony_ci fi.emit('data', 'bar'); 3881cb0ef41Sopenharmony_ci assert.strictEqual(keys.join(''), 'fooXbar'); 3891cb0ef41Sopenharmony_ci rli.close(); 3901cb0ef41Sopenharmony_ci} 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci// History is bound 3931cb0ef41Sopenharmony_ci{ 3941cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, historySize: 2 }); 3951cb0ef41Sopenharmony_ci const lines = ['line 1', 'line 2', 'line 3']; 3961cb0ef41Sopenharmony_ci fi.emit('data', lines.join('\n') + '\n'); 3971cb0ef41Sopenharmony_ci assert.strictEqual(rli.history.length, 2); 3981cb0ef41Sopenharmony_ci assert.strictEqual(rli.history[0], 'line 3'); 3991cb0ef41Sopenharmony_ci assert.strictEqual(rli.history[1], 'line 2'); 4001cb0ef41Sopenharmony_ci} 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci// Question 4031cb0ef41Sopenharmony_ci{ 4041cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal: true }); 4051cb0ef41Sopenharmony_ci const expectedLines = ['foo']; 4061cb0ef41Sopenharmony_ci rli.question(expectedLines[0], () => rli.close()); 4071cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, expectedLines[0].length); 4081cb0ef41Sopenharmony_ci rli.close(); 4091cb0ef41Sopenharmony_ci} 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_ci// Sending a multi-line question 4121cb0ef41Sopenharmony_ci{ 4131cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal: true }); 4141cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar']; 4151cb0ef41Sopenharmony_ci rli.question(expectedLines.join('\n'), () => rli.close()); 4161cb0ef41Sopenharmony_ci assertCursorRowsAndCols( 4171cb0ef41Sopenharmony_ci rli, expectedLines.length - 1, expectedLines.slice(-1)[0].length); 4181cb0ef41Sopenharmony_ci rli.close(); 4191cb0ef41Sopenharmony_ci} 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_ci{ 4221cb0ef41Sopenharmony_ci // Beginning and end of line 4231cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4241cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 4251cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 4261cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 4271cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'e' }); 4281cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 4291cb0ef41Sopenharmony_ci rli.close(); 4301cb0ef41Sopenharmony_ci} 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ci{ 4331cb0ef41Sopenharmony_ci // Back and Forward one character 4341cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4351cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 4361cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 4371cb0ef41Sopenharmony_ci 4381cb0ef41Sopenharmony_ci // Back one character 4391cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'b' }); 4401cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 18); 4411cb0ef41Sopenharmony_ci // Back one character 4421cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'b' }); 4431cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 17); 4441cb0ef41Sopenharmony_ci // Forward one character 4451cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 4461cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 18); 4471cb0ef41Sopenharmony_ci // Forward one character 4481cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 4491cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 4501cb0ef41Sopenharmony_ci rli.close(); 4511cb0ef41Sopenharmony_ci} 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci// Back and Forward one astral character 4541cb0ef41Sopenharmony_ci{ 4551cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4561cb0ef41Sopenharmony_ci fi.emit('data', ''); 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_ci // Move left one character/code point 4591cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'left' }); 4601cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ci // Move right one character/code point 4631cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'right' }); 4641cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 2); 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 4671cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 4681cb0ef41Sopenharmony_ci })); 4691cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 4701cb0ef41Sopenharmony_ci rli.close(); 4711cb0ef41Sopenharmony_ci} 4721cb0ef41Sopenharmony_ci 4731cb0ef41Sopenharmony_ci// Two astral characters left 4741cb0ef41Sopenharmony_ci{ 4751cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4761cb0ef41Sopenharmony_ci fi.emit('data', ''); 4771cb0ef41Sopenharmony_ci 4781cb0ef41Sopenharmony_ci // Move left one character/code point 4791cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'left' }); 4801cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 4811cb0ef41Sopenharmony_ci 4821cb0ef41Sopenharmony_ci fi.emit('data', ''); 4831cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 2); 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 4861cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 4871cb0ef41Sopenharmony_ci })); 4881cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 4891cb0ef41Sopenharmony_ci rli.close(); 4901cb0ef41Sopenharmony_ci} 4911cb0ef41Sopenharmony_ci 4921cb0ef41Sopenharmony_ci// Two astral characters right 4931cb0ef41Sopenharmony_ci{ 4941cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4951cb0ef41Sopenharmony_ci fi.emit('data', ''); 4961cb0ef41Sopenharmony_ci 4971cb0ef41Sopenharmony_ci // Move left one character/code point 4981cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'right' }); 4991cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 2); 5001cb0ef41Sopenharmony_ci 5011cb0ef41Sopenharmony_ci fi.emit('data', ''); 5021cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 4); 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5051cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 5061cb0ef41Sopenharmony_ci })); 5071cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5081cb0ef41Sopenharmony_ci rli.close(); 5091cb0ef41Sopenharmony_ci} 5101cb0ef41Sopenharmony_ci 5111cb0ef41Sopenharmony_ci{ 5121cb0ef41Sopenharmony_ci // `wordLeft` and `wordRight` 5131cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5141cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5151cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'left' }); 5161cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 16); 5171cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { meta: true, name: 'b' }); 5181cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 10); 5191cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'right' }); 5201cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 16); 5211cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { meta: true, name: 'f' }); 5221cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 5231cb0ef41Sopenharmony_ci rli.close(); 5241cb0ef41Sopenharmony_ci} 5251cb0ef41Sopenharmony_ci 5261cb0ef41Sopenharmony_ci// `deleteWordLeft` 5271cb0ef41Sopenharmony_ci[ 5281cb0ef41Sopenharmony_ci { ctrl: true, name: 'w' }, 5291cb0ef41Sopenharmony_ci { ctrl: true, name: 'backspace' }, 5301cb0ef41Sopenharmony_ci { meta: true, name: 'backspace' }, 5311cb0ef41Sopenharmony_ci].forEach((deleteWordLeftKey) => { 5321cb0ef41Sopenharmony_ci let [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5331cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5341cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'left' }); 5351cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5361cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick fox'); 5371cb0ef41Sopenharmony_ci })); 5381cb0ef41Sopenharmony_ci fi.emit('keypress', '.', deleteWordLeftKey); 5391cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5401cb0ef41Sopenharmony_ci rli.close(); 5411cb0ef41Sopenharmony_ci 5421cb0ef41Sopenharmony_ci // No effect if pressed at beginning of line 5431cb0ef41Sopenharmony_ci [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5441cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5451cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 5461cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5471cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick brown fox'); 5481cb0ef41Sopenharmony_ci })); 5491cb0ef41Sopenharmony_ci fi.emit('keypress', '.', deleteWordLeftKey); 5501cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5511cb0ef41Sopenharmony_ci rli.close(); 5521cb0ef41Sopenharmony_ci}); 5531cb0ef41Sopenharmony_ci 5541cb0ef41Sopenharmony_ci// `deleteWordRight` 5551cb0ef41Sopenharmony_ci[ 5561cb0ef41Sopenharmony_ci { ctrl: true, name: 'delete' }, 5571cb0ef41Sopenharmony_ci { meta: true, name: 'delete' }, 5581cb0ef41Sopenharmony_ci { meta: true, name: 'd' }, 5591cb0ef41Sopenharmony_ci].forEach((deleteWordRightKey) => { 5601cb0ef41Sopenharmony_ci let [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5611cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5621cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'left' }); 5631cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'left' }); 5641cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5651cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick fox'); 5661cb0ef41Sopenharmony_ci })); 5671cb0ef41Sopenharmony_ci fi.emit('keypress', '.', deleteWordRightKey); 5681cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5691cb0ef41Sopenharmony_ci rli.close(); 5701cb0ef41Sopenharmony_ci 5711cb0ef41Sopenharmony_ci // No effect if pressed at end of line 5721cb0ef41Sopenharmony_ci [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5731cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5741cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5751cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick brown fox'); 5761cb0ef41Sopenharmony_ci })); 5771cb0ef41Sopenharmony_ci fi.emit('keypress', '.', deleteWordRightKey); 5781cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5791cb0ef41Sopenharmony_ci rli.close(); 5801cb0ef41Sopenharmony_ci}); 5811cb0ef41Sopenharmony_ci 5821cb0ef41Sopenharmony_ci// deleteLeft 5831cb0ef41Sopenharmony_ci{ 5841cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5851cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5861cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 5871cb0ef41Sopenharmony_ci 5881cb0ef41Sopenharmony_ci // Delete left character 5891cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'h' }); 5901cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 18); 5911cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5921cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick brown fo'); 5931cb0ef41Sopenharmony_ci })); 5941cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5951cb0ef41Sopenharmony_ci rli.close(); 5961cb0ef41Sopenharmony_ci} 5971cb0ef41Sopenharmony_ci 5981cb0ef41Sopenharmony_ci// deleteLeft astral character 5991cb0ef41Sopenharmony_ci{ 6001cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6011cb0ef41Sopenharmony_ci fi.emit('data', ''); 6021cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 2); 6031cb0ef41Sopenharmony_ci // Delete left character 6041cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'h' }); 6051cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6061cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 6071cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 6081cb0ef41Sopenharmony_ci })); 6091cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 6101cb0ef41Sopenharmony_ci rli.close(); 6111cb0ef41Sopenharmony_ci} 6121cb0ef41Sopenharmony_ci 6131cb0ef41Sopenharmony_ci// deleteRight 6141cb0ef41Sopenharmony_ci{ 6151cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6161cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 6171cb0ef41Sopenharmony_ci 6181cb0ef41Sopenharmony_ci // Go to the start of the line 6191cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 6201cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6211cb0ef41Sopenharmony_ci 6221cb0ef41Sopenharmony_ci // Delete right character 6231cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'd' }); 6241cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6251cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 6261cb0ef41Sopenharmony_ci assert.strictEqual(line, 'he quick brown fox'); 6271cb0ef41Sopenharmony_ci })); 6281cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 6291cb0ef41Sopenharmony_ci rli.close(); 6301cb0ef41Sopenharmony_ci} 6311cb0ef41Sopenharmony_ci 6321cb0ef41Sopenharmony_ci// deleteRight astral character 6331cb0ef41Sopenharmony_ci{ 6341cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6351cb0ef41Sopenharmony_ci fi.emit('data', ''); 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_ci // Go to the start of the line 6381cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 6391cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6401cb0ef41Sopenharmony_ci 6411cb0ef41Sopenharmony_ci // Delete right character 6421cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'd' }); 6431cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6441cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 6451cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 6461cb0ef41Sopenharmony_ci })); 6471cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 6481cb0ef41Sopenharmony_ci rli.close(); 6491cb0ef41Sopenharmony_ci} 6501cb0ef41Sopenharmony_ci 6511cb0ef41Sopenharmony_ci// deleteLineLeft 6521cb0ef41Sopenharmony_ci{ 6531cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6541cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 6551cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 6561cb0ef41Sopenharmony_ci 6571cb0ef41Sopenharmony_ci // Delete from current to start of line 6581cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'backspace' }); 6591cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6601cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 6611cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 6621cb0ef41Sopenharmony_ci })); 6631cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 6641cb0ef41Sopenharmony_ci rli.close(); 6651cb0ef41Sopenharmony_ci} 6661cb0ef41Sopenharmony_ci 6671cb0ef41Sopenharmony_ci// deleteLineRight 6681cb0ef41Sopenharmony_ci{ 6691cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6701cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 6711cb0ef41Sopenharmony_ci 6721cb0ef41Sopenharmony_ci // Go to the start of the line 6731cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 6741cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6751cb0ef41Sopenharmony_ci 6761cb0ef41Sopenharmony_ci // Delete from current to end of line 6771cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'delete' }); 6781cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6791cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 6801cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 6811cb0ef41Sopenharmony_ci })); 6821cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 6831cb0ef41Sopenharmony_ci rli.close(); 6841cb0ef41Sopenharmony_ci} 6851cb0ef41Sopenharmony_ci 6861cb0ef41Sopenharmony_ci// yank 6871cb0ef41Sopenharmony_ci{ 6881cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6891cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 6901cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 6911cb0ef41Sopenharmony_ci 6921cb0ef41Sopenharmony_ci // Go to the start of the line 6931cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 6941cb0ef41Sopenharmony_ci // Move forward one char 6951cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 6961cb0ef41Sopenharmony_ci // Delete the right part 6971cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'delete' }); 6981cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 1); 6991cb0ef41Sopenharmony_ci 7001cb0ef41Sopenharmony_ci // Yank 7011cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'y' }); 7021cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 7031cb0ef41Sopenharmony_ci 7041cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 7051cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick brown fox'); 7061cb0ef41Sopenharmony_ci })); 7071cb0ef41Sopenharmony_ci 7081cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 7091cb0ef41Sopenharmony_ci rli.close(); 7101cb0ef41Sopenharmony_ci} 7111cb0ef41Sopenharmony_ci 7121cb0ef41Sopenharmony_ci// yank pop 7131cb0ef41Sopenharmony_ci{ 7141cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 7151cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 7161cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 7171cb0ef41Sopenharmony_ci 7181cb0ef41Sopenharmony_ci // Go to the start of the line 7191cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 7201cb0ef41Sopenharmony_ci // Move forward one char 7211cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 7221cb0ef41Sopenharmony_ci // Delete the right part 7231cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'delete' }); 7241cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 1); 7251cb0ef41Sopenharmony_ci // Yank 7261cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'y' }); 7271cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 7281cb0ef41Sopenharmony_ci 7291cb0ef41Sopenharmony_ci // Go to the start of the line 7301cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 7311cb0ef41Sopenharmony_ci // Move forward four chars 7321cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 7331cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 7341cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 7351cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 7361cb0ef41Sopenharmony_ci // Delete the right part 7371cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'delete' }); 7381cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 4); 7391cb0ef41Sopenharmony_ci // Go to the start of the line 7401cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 7411cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 7421cb0ef41Sopenharmony_ci 7431cb0ef41Sopenharmony_ci // Yank: 'quick brown fox|the ' 7441cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'y' }); 7451cb0ef41Sopenharmony_ci // Yank pop: 'he quick brown fox|the' 7461cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { meta: true, name: 'y' }); 7471cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 18); 7481cb0ef41Sopenharmony_ci 7491cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 7501cb0ef41Sopenharmony_ci assert.strictEqual(line, 'he quick brown foxthe '); 7511cb0ef41Sopenharmony_ci })); 7521cb0ef41Sopenharmony_ci 7531cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 7541cb0ef41Sopenharmony_ci rli.close(); 7551cb0ef41Sopenharmony_ci} 7561cb0ef41Sopenharmony_ci 7571cb0ef41Sopenharmony_ci// Close readline interface 7581cb0ef41Sopenharmony_ci{ 7591cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 7601cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'c' }); 7611cb0ef41Sopenharmony_ci assert(rli.closed); 7621cb0ef41Sopenharmony_ci} 7631cb0ef41Sopenharmony_ci 7641cb0ef41Sopenharmony_ci// Multi-line input cursor position 7651cb0ef41Sopenharmony_ci{ 7661cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 7671cb0ef41Sopenharmony_ci fi.columns = 10; 7681cb0ef41Sopenharmony_ci fi.emit('data', 'multi-line text'); 7691cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 1, 5); 7701cb0ef41Sopenharmony_ci rli.close(); 7711cb0ef41Sopenharmony_ci} 7721cb0ef41Sopenharmony_ci 7731cb0ef41Sopenharmony_ci// Multi-line input cursor position and long tabs 7741cb0ef41Sopenharmony_ci{ 7751cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ tabSize: 16, terminal: true, prompt: '' }); 7761cb0ef41Sopenharmony_ci fi.columns = 10; 7771cb0ef41Sopenharmony_ci fi.emit('data', 'multi-line\ttext \t'); 7781cb0ef41Sopenharmony_ci assert.strictEqual(rli.cursor, 17); 7791cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 3, 2); 7801cb0ef41Sopenharmony_ci rli.close(); 7811cb0ef41Sopenharmony_ci} 7821cb0ef41Sopenharmony_ci 7831cb0ef41Sopenharmony_ci// Check for the default tab size. 7841cb0ef41Sopenharmony_ci{ 7851cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 7861cb0ef41Sopenharmony_ci fi.emit('data', 'the quick\tbrown\tfox'); 7871cb0ef41Sopenharmony_ci assert.strictEqual(rli.cursor, 19); 7881cb0ef41Sopenharmony_ci // The first tab is 7 spaces long, the second one 3 spaces. 7891cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 27); 7901cb0ef41Sopenharmony_ci} 7911cb0ef41Sopenharmony_ci 7921cb0ef41Sopenharmony_ci// Multi-line prompt cursor position 7931cb0ef41Sopenharmony_ci{ 7941cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ 7951cb0ef41Sopenharmony_ci terminal: true, 7961cb0ef41Sopenharmony_ci prompt: '\nfilledline\nwraping text\n> ' 7971cb0ef41Sopenharmony_ci }); 7981cb0ef41Sopenharmony_ci fi.columns = 10; 7991cb0ef41Sopenharmony_ci fi.emit('data', 't'); 8001cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 4, 3); 8011cb0ef41Sopenharmony_ci rli.close(); 8021cb0ef41Sopenharmony_ci} 8031cb0ef41Sopenharmony_ci 8041cb0ef41Sopenharmony_ci// Undo & Redo 8051cb0ef41Sopenharmony_ci{ 8061cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 8071cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 8081cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 8091cb0ef41Sopenharmony_ci 8101cb0ef41Sopenharmony_ci // Delete the last eight chars 8111cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); 8121cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); 8131cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); 8141cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); 8151cb0ef41Sopenharmony_ci fi.emit('keypress', ',', { ctrl: true, shift: false, name: 'k' }); 8161cb0ef41Sopenharmony_ci 8171cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); 8181cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); 8191cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); 8201cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); 8211cb0ef41Sopenharmony_ci fi.emit('keypress', ',', { ctrl: true, shift: false, name: 'k' }); 8221cb0ef41Sopenharmony_ci 8231cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 11); 8241cb0ef41Sopenharmony_ci // Perform undo twice 8251cb0ef41Sopenharmony_ci fi.emit('keypress', ',', { sequence: '\x1F' }); 8261cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'the quick brown'); 8271cb0ef41Sopenharmony_ci fi.emit('keypress', ',', { sequence: '\x1F' }); 8281cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'the quick brown fox'); 8291cb0ef41Sopenharmony_ci // Perform redo twice 8301cb0ef41Sopenharmony_ci fi.emit('keypress', ',', { sequence: '\x1E' }); 8311cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'the quick brown'); 8321cb0ef41Sopenharmony_ci fi.emit('keypress', ',', { sequence: '\x1E' }); 8331cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'the quick b'); 8341cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 8351cb0ef41Sopenharmony_ci rli.close(); 8361cb0ef41Sopenharmony_ci} 8371cb0ef41Sopenharmony_ci 8381cb0ef41Sopenharmony_ci// Clear the whole screen 8391cb0ef41Sopenharmony_ci{ 8401cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 8411cb0ef41Sopenharmony_ci const lines = ['line 1', 'line 2', 'line 3']; 8421cb0ef41Sopenharmony_ci fi.emit('data', lines.join('\n')); 8431cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'l' }); 8441cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 6); 8451cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 8461cb0ef41Sopenharmony_ci assert.strictEqual(line, 'line 3'); 8471cb0ef41Sopenharmony_ci })); 8481cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 8491cb0ef41Sopenharmony_ci rli.close(); 8501cb0ef41Sopenharmony_ci} 8511cb0ef41Sopenharmony_ci 8521cb0ef41Sopenharmony_ci// Wide characters should be treated as two columns. 8531cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('a'), 1); 8541cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('あ'), 2); 8551cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('谢'), 2); 8561cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('고'), 2); 8571cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCodePoint(0x1f251)), 2); 8581cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('abcde'), 5); 8591cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('古池や'), 6); 8601cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('ノード.js'), 9); 8611cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('你好'), 4); 8621cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('안녕하세요'), 10); 8631cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('A\ud83c\ude00BC'), 5); 8641cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(''), 8); 8651cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('あ'), 9); 8661cb0ef41Sopenharmony_ci// TODO(BridgeAR): This should have a width of 4. 8671cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('⓬⓪'), 2); 8681cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u0301\u200D\u200E'), 0); 8691cb0ef41Sopenharmony_ci 8701cb0ef41Sopenharmony_ci// Check if vt control chars are stripped 8711cb0ef41Sopenharmony_ciassert.strictEqual(stripVTControlCharacters('\u001b[31m> \u001b[39m'), '> '); 8721cb0ef41Sopenharmony_ciassert.strictEqual( 8731cb0ef41Sopenharmony_ci stripVTControlCharacters('\u001b[31m> \u001b[39m> '), 8741cb0ef41Sopenharmony_ci '> > ' 8751cb0ef41Sopenharmony_ci); 8761cb0ef41Sopenharmony_ciassert.strictEqual(stripVTControlCharacters('\u001b[31m\u001b[39m'), ''); 8771cb0ef41Sopenharmony_ciassert.strictEqual(stripVTControlCharacters('> '), '> '); 8781cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u001b[31m> \u001b[39m'), 2); 8791cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u001b[31m> \u001b[39m> '), 4); 8801cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u001b[31m\u001b[39m'), 0); 8811cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('> '), 2); 8821cb0ef41Sopenharmony_ci 8831cb0ef41Sopenharmony_ci// Check EventEmitter memory leak 8841cb0ef41Sopenharmony_cifor (let i = 0; i < 12; i++) { 8851cb0ef41Sopenharmony_ci const rl = readline.createInterface({ 8861cb0ef41Sopenharmony_ci input: process.stdin, 8871cb0ef41Sopenharmony_ci output: process.stdout 8881cb0ef41Sopenharmony_ci }); 8891cb0ef41Sopenharmony_ci rl.close(); 8901cb0ef41Sopenharmony_ci assert.strictEqual(isWarned(process.stdin._events), false); 8911cb0ef41Sopenharmony_ci assert.strictEqual(isWarned(process.stdout._events), false); 8921cb0ef41Sopenharmony_ci} 8931cb0ef41Sopenharmony_ci 8941cb0ef41Sopenharmony_ci[true, false].forEach((terminal) => { 8951cb0ef41Sopenharmony_ci // Disable history 8961cb0ef41Sopenharmony_ci { 8971cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, historySize: 0 }); 8981cb0ef41Sopenharmony_ci assert.strictEqual(rli.historySize, 0); 8991cb0ef41Sopenharmony_ci 9001cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 9011cb0ef41Sopenharmony_ci assert.deepStrictEqual(rli.history, []); 9021cb0ef41Sopenharmony_ci rli.close(); 9031cb0ef41Sopenharmony_ci } 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_ci // Default history size 30 9061cb0ef41Sopenharmony_ci { 9071cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 9081cb0ef41Sopenharmony_ci assert.strictEqual(rli.historySize, 30); 9091cb0ef41Sopenharmony_ci 9101cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 9111cb0ef41Sopenharmony_ci assert.deepStrictEqual(rli.history, terminal ? ['asdf'] : []); 9121cb0ef41Sopenharmony_ci rli.close(); 9131cb0ef41Sopenharmony_ci } 9141cb0ef41Sopenharmony_ci 9151cb0ef41Sopenharmony_ci // Sending a full line 9161cb0ef41Sopenharmony_ci { 9171cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 9181cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 9191cb0ef41Sopenharmony_ci assert.strictEqual(line, 'asdf'); 9201cb0ef41Sopenharmony_ci })); 9211cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 9221cb0ef41Sopenharmony_ci } 9231cb0ef41Sopenharmony_ci 9241cb0ef41Sopenharmony_ci // Ensure that options.signal.removeEventListener was called 9251cb0ef41Sopenharmony_ci { 9261cb0ef41Sopenharmony_ci const ac = new AbortController(); 9271cb0ef41Sopenharmony_ci const signal = ac.signal; 9281cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 9291cb0ef41Sopenharmony_ci signal.removeEventListener = common.mustCall( 9301cb0ef41Sopenharmony_ci (event, onAbortFn) => { 9311cb0ef41Sopenharmony_ci assert.strictEqual(event, 'abort'); 9321cb0ef41Sopenharmony_ci assert.strictEqual(onAbortFn.name, 'onAbort'); 9331cb0ef41Sopenharmony_ci }); 9341cb0ef41Sopenharmony_ci 9351cb0ef41Sopenharmony_ci rli.question('hello?', { signal }, common.mustCall()); 9361cb0ef41Sopenharmony_ci 9371cb0ef41Sopenharmony_ci rli.write('bar\n'); 9381cb0ef41Sopenharmony_ci ac.abort(); 9391cb0ef41Sopenharmony_ci rli.close(); 9401cb0ef41Sopenharmony_ci } 9411cb0ef41Sopenharmony_ci 9421cb0ef41Sopenharmony_ci // Sending a blank line 9431cb0ef41Sopenharmony_ci { 9441cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 9451cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 9461cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 9471cb0ef41Sopenharmony_ci })); 9481cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 9491cb0ef41Sopenharmony_ci } 9501cb0ef41Sopenharmony_ci 9511cb0ef41Sopenharmony_ci // Sending a single character with no newline and then a newline 9521cb0ef41Sopenharmony_ci { 9531cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 9541cb0ef41Sopenharmony_ci let called = false; 9551cb0ef41Sopenharmony_ci rli.on('line', (line) => { 9561cb0ef41Sopenharmony_ci called = true; 9571cb0ef41Sopenharmony_ci assert.strictEqual(line, 'a'); 9581cb0ef41Sopenharmony_ci }); 9591cb0ef41Sopenharmony_ci fi.emit('data', 'a'); 9601cb0ef41Sopenharmony_ci assert.ok(!called); 9611cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 9621cb0ef41Sopenharmony_ci assert.ok(called); 9631cb0ef41Sopenharmony_ci rli.close(); 9641cb0ef41Sopenharmony_ci } 9651cb0ef41Sopenharmony_ci 9661cb0ef41Sopenharmony_ci // Sending multiple newlines at once 9671cb0ef41Sopenharmony_ci { 9681cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 9691cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz']; 9701cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 9711cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 9721cb0ef41Sopenharmony_ci }, expectedLines.length)); 9731cb0ef41Sopenharmony_ci fi.emit('data', `${expectedLines.join('\n')}\n`); 9741cb0ef41Sopenharmony_ci rli.close(); 9751cb0ef41Sopenharmony_ci } 9761cb0ef41Sopenharmony_ci 9771cb0ef41Sopenharmony_ci // Sending multiple newlines at once that does not end with a new line 9781cb0ef41Sopenharmony_ci { 9791cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 9801cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 9811cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 9821cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 9831cb0ef41Sopenharmony_ci }, expectedLines.length - 1)); 9841cb0ef41Sopenharmony_ci fi.emit('data', expectedLines.join('\n')); 9851cb0ef41Sopenharmony_ci rli.close(); 9861cb0ef41Sopenharmony_ci } 9871cb0ef41Sopenharmony_ci 9881cb0ef41Sopenharmony_ci // Sending multiple newlines at once that does not end with a new(empty) 9891cb0ef41Sopenharmony_ci // line and a `end` event 9901cb0ef41Sopenharmony_ci { 9911cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 9921cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', '']; 9931cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 9941cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 9951cb0ef41Sopenharmony_ci }, expectedLines.length - 1)); 9961cb0ef41Sopenharmony_ci rli.on('close', common.mustCall()); 9971cb0ef41Sopenharmony_ci fi.emit('data', expectedLines.join('\n')); 9981cb0ef41Sopenharmony_ci fi.emit('end'); 9991cb0ef41Sopenharmony_ci rli.close(); 10001cb0ef41Sopenharmony_ci } 10011cb0ef41Sopenharmony_ci 10021cb0ef41Sopenharmony_ci // Sending a multi-byte utf8 char over multiple writes 10031cb0ef41Sopenharmony_ci { 10041cb0ef41Sopenharmony_ci const buf = Buffer.from('☮', 'utf8'); 10051cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 10061cb0ef41Sopenharmony_ci let callCount = 0; 10071cb0ef41Sopenharmony_ci rli.on('line', (line) => { 10081cb0ef41Sopenharmony_ci callCount++; 10091cb0ef41Sopenharmony_ci assert.strictEqual(line, buf.toString('utf8')); 10101cb0ef41Sopenharmony_ci }); 10111cb0ef41Sopenharmony_ci for (const i of buf) { 10121cb0ef41Sopenharmony_ci fi.emit('data', Buffer.from([i])); 10131cb0ef41Sopenharmony_ci } 10141cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 0); 10151cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 10161cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 1); 10171cb0ef41Sopenharmony_ci rli.close(); 10181cb0ef41Sopenharmony_ci } 10191cb0ef41Sopenharmony_ci 10201cb0ef41Sopenharmony_ci // Calling readline without `new` 10211cb0ef41Sopenharmony_ci { 10221cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 10231cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 10241cb0ef41Sopenharmony_ci assert.strictEqual(line, 'asdf'); 10251cb0ef41Sopenharmony_ci })); 10261cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 10271cb0ef41Sopenharmony_ci rli.close(); 10281cb0ef41Sopenharmony_ci } 10291cb0ef41Sopenharmony_ci 10301cb0ef41Sopenharmony_ci // Calling the question callback 10311cb0ef41Sopenharmony_ci { 10321cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 10331cb0ef41Sopenharmony_ci rli.question('foo?', common.mustCall((answer) => { 10341cb0ef41Sopenharmony_ci assert.strictEqual(answer, 'bar'); 10351cb0ef41Sopenharmony_ci })); 10361cb0ef41Sopenharmony_ci rli.write('bar\n'); 10371cb0ef41Sopenharmony_ci rli.close(); 10381cb0ef41Sopenharmony_ci } 10391cb0ef41Sopenharmony_ci 10401cb0ef41Sopenharmony_ci // Calling the question callback with abort signal 10411cb0ef41Sopenharmony_ci { 10421cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 10431cb0ef41Sopenharmony_ci const { signal } = new AbortController(); 10441cb0ef41Sopenharmony_ci rli.question('foo?', { signal }, common.mustCall((answer) => { 10451cb0ef41Sopenharmony_ci assert.strictEqual(answer, 'bar'); 10461cb0ef41Sopenharmony_ci })); 10471cb0ef41Sopenharmony_ci rli.write('bar\n'); 10481cb0ef41Sopenharmony_ci rli.close(); 10491cb0ef41Sopenharmony_ci } 10501cb0ef41Sopenharmony_ci 10511cb0ef41Sopenharmony_ci // Calling the question multiple times 10521cb0ef41Sopenharmony_ci { 10531cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 10541cb0ef41Sopenharmony_ci rli.question('foo?', common.mustCall((answer) => { 10551cb0ef41Sopenharmony_ci assert.strictEqual(answer, 'baz'); 10561cb0ef41Sopenharmony_ci })); 10571cb0ef41Sopenharmony_ci rli.question('bar?', common.mustNotCall()); 10581cb0ef41Sopenharmony_ci rli.write('baz\n'); 10591cb0ef41Sopenharmony_ci rli.close(); 10601cb0ef41Sopenharmony_ci } 10611cb0ef41Sopenharmony_ci 10621cb0ef41Sopenharmony_ci // Calling the promisified question 10631cb0ef41Sopenharmony_ci { 10641cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 10651cb0ef41Sopenharmony_ci const question = util.promisify(rli.question).bind(rli); 10661cb0ef41Sopenharmony_ci question('foo?') 10671cb0ef41Sopenharmony_ci .then(common.mustCall((answer) => { 10681cb0ef41Sopenharmony_ci assert.strictEqual(answer, 'bar'); 10691cb0ef41Sopenharmony_ci })); 10701cb0ef41Sopenharmony_ci rli.write('bar\n'); 10711cb0ef41Sopenharmony_ci rli.close(); 10721cb0ef41Sopenharmony_ci } 10731cb0ef41Sopenharmony_ci 10741cb0ef41Sopenharmony_ci // Calling the promisified question with abort signal 10751cb0ef41Sopenharmony_ci { 10761cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 10771cb0ef41Sopenharmony_ci const question = util.promisify(rli.question).bind(rli); 10781cb0ef41Sopenharmony_ci const { signal } = new AbortController(); 10791cb0ef41Sopenharmony_ci question('foo?', { signal }) 10801cb0ef41Sopenharmony_ci .then(common.mustCall((answer) => { 10811cb0ef41Sopenharmony_ci assert.strictEqual(answer, 'bar'); 10821cb0ef41Sopenharmony_ci })); 10831cb0ef41Sopenharmony_ci rli.write('bar\n'); 10841cb0ef41Sopenharmony_ci rli.close(); 10851cb0ef41Sopenharmony_ci } 10861cb0ef41Sopenharmony_ci 10871cb0ef41Sopenharmony_ci // Aborting a question 10881cb0ef41Sopenharmony_ci { 10891cb0ef41Sopenharmony_ci const ac = new AbortController(); 10901cb0ef41Sopenharmony_ci const signal = ac.signal; 10911cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 10921cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 10931cb0ef41Sopenharmony_ci assert.strictEqual(line, 'bar'); 10941cb0ef41Sopenharmony_ci })); 10951cb0ef41Sopenharmony_ci rli.question('hello?', { signal }, common.mustNotCall()); 10961cb0ef41Sopenharmony_ci ac.abort(); 10971cb0ef41Sopenharmony_ci rli.write('bar\n'); 10981cb0ef41Sopenharmony_ci rli.close(); 10991cb0ef41Sopenharmony_ci } 11001cb0ef41Sopenharmony_ci 11011cb0ef41Sopenharmony_ci // Aborting a promisified question 11021cb0ef41Sopenharmony_ci { 11031cb0ef41Sopenharmony_ci const ac = new AbortController(); 11041cb0ef41Sopenharmony_ci const signal = ac.signal; 11051cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 11061cb0ef41Sopenharmony_ci const question = util.promisify(rli.question).bind(rli); 11071cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 11081cb0ef41Sopenharmony_ci assert.strictEqual(line, 'bar'); 11091cb0ef41Sopenharmony_ci })); 11101cb0ef41Sopenharmony_ci question('hello?', { signal }) 11111cb0ef41Sopenharmony_ci .then(common.mustNotCall()) 11121cb0ef41Sopenharmony_ci .catch(common.mustCall((error) => { 11131cb0ef41Sopenharmony_ci assert.strictEqual(error.name, 'AbortError'); 11141cb0ef41Sopenharmony_ci })); 11151cb0ef41Sopenharmony_ci ac.abort(); 11161cb0ef41Sopenharmony_ci rli.write('bar\n'); 11171cb0ef41Sopenharmony_ci rli.close(); 11181cb0ef41Sopenharmony_ci } 11191cb0ef41Sopenharmony_ci 11201cb0ef41Sopenharmony_ci // pre-aborted signal 11211cb0ef41Sopenharmony_ci { 11221cb0ef41Sopenharmony_ci const signal = AbortSignal.abort(); 11231cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 11241cb0ef41Sopenharmony_ci rli.pause(); 11251cb0ef41Sopenharmony_ci rli.on('resume', common.mustNotCall()); 11261cb0ef41Sopenharmony_ci rli.question('hello?', { signal }, common.mustNotCall()); 11271cb0ef41Sopenharmony_ci rli.close(); 11281cb0ef41Sopenharmony_ci } 11291cb0ef41Sopenharmony_ci 11301cb0ef41Sopenharmony_ci // pre-aborted signal promisified question 11311cb0ef41Sopenharmony_ci { 11321cb0ef41Sopenharmony_ci const signal = AbortSignal.abort(); 11331cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 11341cb0ef41Sopenharmony_ci const question = util.promisify(rli.question).bind(rli); 11351cb0ef41Sopenharmony_ci rli.on('resume', common.mustNotCall()); 11361cb0ef41Sopenharmony_ci rli.pause(); 11371cb0ef41Sopenharmony_ci question('hello?', { signal }) 11381cb0ef41Sopenharmony_ci .then(common.mustNotCall()) 11391cb0ef41Sopenharmony_ci .catch(common.mustCall((error) => { 11401cb0ef41Sopenharmony_ci assert.strictEqual(error.name, 'AbortError'); 11411cb0ef41Sopenharmony_ci })); 11421cb0ef41Sopenharmony_ci rli.close(); 11431cb0ef41Sopenharmony_ci } 11441cb0ef41Sopenharmony_ci 11451cb0ef41Sopenharmony_ci // Call question after close 11461cb0ef41Sopenharmony_ci { 11471cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 11481cb0ef41Sopenharmony_ci rli.question('What\'s your name?', common.mustCall((name) => { 11491cb0ef41Sopenharmony_ci assert.strictEqual(name, 'Node.js'); 11501cb0ef41Sopenharmony_ci rli.close(); 11511cb0ef41Sopenharmony_ci assert.throws(() => { 11521cb0ef41Sopenharmony_ci rli.question('How are you?', common.mustNotCall()); 11531cb0ef41Sopenharmony_ci }, { 11541cb0ef41Sopenharmony_ci name: 'Error', 11551cb0ef41Sopenharmony_ci code: 'ERR_USE_AFTER_CLOSE' 11561cb0ef41Sopenharmony_ci }); 11571cb0ef41Sopenharmony_ci assert.notStrictEqual(rli.getPrompt(), 'How are you?'); 11581cb0ef41Sopenharmony_ci })); 11591cb0ef41Sopenharmony_ci fi.emit('data', 'Node.js\n'); 11601cb0ef41Sopenharmony_ci } 11611cb0ef41Sopenharmony_ci 11621cb0ef41Sopenharmony_ci // Call promisified question after close 11631cb0ef41Sopenharmony_ci { 11641cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 11651cb0ef41Sopenharmony_ci const question = util.promisify(rli.question).bind(rli); 11661cb0ef41Sopenharmony_ci question('What\'s your name?').then(common.mustCall((name) => { 11671cb0ef41Sopenharmony_ci assert.strictEqual(name, 'Node.js'); 11681cb0ef41Sopenharmony_ci rli.close(); 11691cb0ef41Sopenharmony_ci question('How are you?') 11701cb0ef41Sopenharmony_ci .then(common.mustNotCall(), common.expectsError({ 11711cb0ef41Sopenharmony_ci code: 'ERR_USE_AFTER_CLOSE', 11721cb0ef41Sopenharmony_ci name: 'Error' 11731cb0ef41Sopenharmony_ci })); 11741cb0ef41Sopenharmony_ci assert.notStrictEqual(rli.getPrompt(), 'How are you?'); 11751cb0ef41Sopenharmony_ci })); 11761cb0ef41Sopenharmony_ci fi.emit('data', 'Node.js\n'); 11771cb0ef41Sopenharmony_ci } 11781cb0ef41Sopenharmony_ci 11791cb0ef41Sopenharmony_ci // Can create a new readline Interface with a null output argument 11801cb0ef41Sopenharmony_ci { 11811cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ output: null, terminal }); 11821cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 11831cb0ef41Sopenharmony_ci assert.strictEqual(line, 'asdf'); 11841cb0ef41Sopenharmony_ci })); 11851cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 11861cb0ef41Sopenharmony_ci 11871cb0ef41Sopenharmony_ci rli.setPrompt('ddd> '); 11881cb0ef41Sopenharmony_ci rli.prompt(); 11891cb0ef41Sopenharmony_ci rli.write("really shouldn't be seeing this"); 11901cb0ef41Sopenharmony_ci rli.question('What do you think of node.js? ', (answer) => { 11911cb0ef41Sopenharmony_ci console.log('Thank you for your valuable feedback:', answer); 11921cb0ef41Sopenharmony_ci rli.close(); 11931cb0ef41Sopenharmony_ci }); 11941cb0ef41Sopenharmony_ci } 11951cb0ef41Sopenharmony_ci 11961cb0ef41Sopenharmony_ci // Calling the getPrompt method 11971cb0ef41Sopenharmony_ci { 11981cb0ef41Sopenharmony_ci const expectedPrompts = ['$ ', '> ']; 11991cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 12001cb0ef41Sopenharmony_ci for (const prompt of expectedPrompts) { 12011cb0ef41Sopenharmony_ci rli.setPrompt(prompt); 12021cb0ef41Sopenharmony_ci assert.strictEqual(rli.getPrompt(), prompt); 12031cb0ef41Sopenharmony_ci } 12041cb0ef41Sopenharmony_ci } 12051cb0ef41Sopenharmony_ci 12061cb0ef41Sopenharmony_ci { 12071cb0ef41Sopenharmony_ci const expected = terminal ? 12081cb0ef41Sopenharmony_ci ['\u001b[1G', '\u001b[0J', '$ ', '\u001b[3G'] : 12091cb0ef41Sopenharmony_ci ['$ ']; 12101cb0ef41Sopenharmony_ci 12111cb0ef41Sopenharmony_ci const output = new Writable({ 12121cb0ef41Sopenharmony_ci write: common.mustCall((chunk, enc, cb) => { 12131cb0ef41Sopenharmony_ci assert.strictEqual(chunk.toString(), expected.shift()); 12141cb0ef41Sopenharmony_ci cb(); 12151cb0ef41Sopenharmony_ci rl.close(); 12161cb0ef41Sopenharmony_ci }, expected.length) 12171cb0ef41Sopenharmony_ci }); 12181cb0ef41Sopenharmony_ci 12191cb0ef41Sopenharmony_ci const rl = readline.createInterface({ 12201cb0ef41Sopenharmony_ci input: new Readable({ read: common.mustCall() }), 12211cb0ef41Sopenharmony_ci output, 12221cb0ef41Sopenharmony_ci prompt: '$ ', 12231cb0ef41Sopenharmony_ci terminal 12241cb0ef41Sopenharmony_ci }); 12251cb0ef41Sopenharmony_ci 12261cb0ef41Sopenharmony_ci rl.prompt(); 12271cb0ef41Sopenharmony_ci 12281cb0ef41Sopenharmony_ci assert.strictEqual(rl.getPrompt(), '$ '); 12291cb0ef41Sopenharmony_ci } 12301cb0ef41Sopenharmony_ci 12311cb0ef41Sopenharmony_ci { 12321cb0ef41Sopenharmony_ci const fi = new FakeInput(); 12331cb0ef41Sopenharmony_ci assert.deepStrictEqual(fi.listeners(terminal ? 'keypress' : 'data'), []); 12341cb0ef41Sopenharmony_ci } 12351cb0ef41Sopenharmony_ci 12361cb0ef41Sopenharmony_ci // Emit two line events when the delay 12371cb0ef41Sopenharmony_ci // between \r and \n exceeds crlfDelay 12381cb0ef41Sopenharmony_ci { 12391cb0ef41Sopenharmony_ci const crlfDelay = 200; 12401cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 12411cb0ef41Sopenharmony_ci let callCount = 0; 12421cb0ef41Sopenharmony_ci rli.on('line', () => { 12431cb0ef41Sopenharmony_ci callCount++; 12441cb0ef41Sopenharmony_ci }); 12451cb0ef41Sopenharmony_ci fi.emit('data', '\r'); 12461cb0ef41Sopenharmony_ci setTimeout(common.mustCall(() => { 12471cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 12481cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 2); 12491cb0ef41Sopenharmony_ci rli.close(); 12501cb0ef41Sopenharmony_ci }), crlfDelay + 10); 12511cb0ef41Sopenharmony_ci } 12521cb0ef41Sopenharmony_ci 12531cb0ef41Sopenharmony_ci // For the purposes of the following tests, we do not care about the exact 12541cb0ef41Sopenharmony_ci // value of crlfDelay, only that the behaviour conforms to what's expected. 12551cb0ef41Sopenharmony_ci // Setting it to Infinity allows the test to succeed even under extreme 12561cb0ef41Sopenharmony_ci // CPU stress. 12571cb0ef41Sopenharmony_ci const crlfDelay = Infinity; 12581cb0ef41Sopenharmony_ci 12591cb0ef41Sopenharmony_ci // Set crlfDelay to `Infinity` is allowed 12601cb0ef41Sopenharmony_ci { 12611cb0ef41Sopenharmony_ci const delay = 200; 12621cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 12631cb0ef41Sopenharmony_ci let callCount = 0; 12641cb0ef41Sopenharmony_ci rli.on('line', () => { 12651cb0ef41Sopenharmony_ci callCount++; 12661cb0ef41Sopenharmony_ci }); 12671cb0ef41Sopenharmony_ci fi.emit('data', '\r'); 12681cb0ef41Sopenharmony_ci setTimeout(common.mustCall(() => { 12691cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 12701cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 1); 12711cb0ef41Sopenharmony_ci rli.close(); 12721cb0ef41Sopenharmony_ci }), delay); 12731cb0ef41Sopenharmony_ci } 12741cb0ef41Sopenharmony_ci 12751cb0ef41Sopenharmony_ci // Sending multiple newlines at once that does not end with a new line 12761cb0ef41Sopenharmony_ci // and a `end` event(last line is) 12771cb0ef41Sopenharmony_ci 12781cb0ef41Sopenharmony_ci // \r\n should emit one line event, not two 12791cb0ef41Sopenharmony_ci { 12801cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 12811cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 12821cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 12831cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 12841cb0ef41Sopenharmony_ci }, expectedLines.length - 1)); 12851cb0ef41Sopenharmony_ci fi.emit('data', expectedLines.join('\r\n')); 12861cb0ef41Sopenharmony_ci rli.close(); 12871cb0ef41Sopenharmony_ci } 12881cb0ef41Sopenharmony_ci 12891cb0ef41Sopenharmony_ci // \r\n should emit one line event when split across multiple writes. 12901cb0ef41Sopenharmony_ci { 12911cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 12921cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 12931cb0ef41Sopenharmony_ci let callCount = 0; 12941cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 12951cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines[callCount]); 12961cb0ef41Sopenharmony_ci callCount++; 12971cb0ef41Sopenharmony_ci }, expectedLines.length)); 12981cb0ef41Sopenharmony_ci expectedLines.forEach((line) => { 12991cb0ef41Sopenharmony_ci fi.emit('data', `${line}\r`); 13001cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 13011cb0ef41Sopenharmony_ci }); 13021cb0ef41Sopenharmony_ci rli.close(); 13031cb0ef41Sopenharmony_ci } 13041cb0ef41Sopenharmony_ci 13051cb0ef41Sopenharmony_ci // Emit one line event when the delay between \r and \n is 13061cb0ef41Sopenharmony_ci // over the default crlfDelay but within the setting value. 13071cb0ef41Sopenharmony_ci { 13081cb0ef41Sopenharmony_ci const delay = 125; 13091cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 13101cb0ef41Sopenharmony_ci let callCount = 0; 13111cb0ef41Sopenharmony_ci rli.on('line', () => callCount++); 13121cb0ef41Sopenharmony_ci fi.emit('data', '\r'); 13131cb0ef41Sopenharmony_ci setTimeout(common.mustCall(() => { 13141cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 13151cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 1); 13161cb0ef41Sopenharmony_ci rli.close(); 13171cb0ef41Sopenharmony_ci }), delay); 13181cb0ef41Sopenharmony_ci } 13191cb0ef41Sopenharmony_ci}); 13201cb0ef41Sopenharmony_ci 13211cb0ef41Sopenharmony_ci// Ensure that the _wordLeft method works even for large input 13221cb0ef41Sopenharmony_ci{ 13231cb0ef41Sopenharmony_ci const input = new Readable({ 13241cb0ef41Sopenharmony_ci read() { 13251cb0ef41Sopenharmony_ci this.push('\x1B[1;5D'); // CTRL + Left 13261cb0ef41Sopenharmony_ci this.push(null); 13271cb0ef41Sopenharmony_ci }, 13281cb0ef41Sopenharmony_ci }); 13291cb0ef41Sopenharmony_ci const output = new Writable({ 13301cb0ef41Sopenharmony_ci write: common.mustCall((data, encoding, cb) => { 13311cb0ef41Sopenharmony_ci assert.strictEqual(rl.cursor, rl.line.length - 1); 13321cb0ef41Sopenharmony_ci cb(); 13331cb0ef41Sopenharmony_ci }), 13341cb0ef41Sopenharmony_ci }); 13351cb0ef41Sopenharmony_ci const rl = new readline.createInterface({ 13361cb0ef41Sopenharmony_ci input, 13371cb0ef41Sopenharmony_ci output, 13381cb0ef41Sopenharmony_ci terminal: true, 13391cb0ef41Sopenharmony_ci }); 13401cb0ef41Sopenharmony_ci rl.line = `a${' '.repeat(1e6)}a`; 13411cb0ef41Sopenharmony_ci rl.cursor = rl.line.length; 13421cb0ef41Sopenharmony_ci} 13431cb0ef41Sopenharmony_ci 13441cb0ef41Sopenharmony_ci{ 13451cb0ef41Sopenharmony_ci const fi = new FakeInput(); 13461cb0ef41Sopenharmony_ci const signal = AbortSignal.abort(); 13471cb0ef41Sopenharmony_ci 13481cb0ef41Sopenharmony_ci const rl = readline.createInterface({ 13491cb0ef41Sopenharmony_ci input: fi, 13501cb0ef41Sopenharmony_ci output: fi, 13511cb0ef41Sopenharmony_ci signal, 13521cb0ef41Sopenharmony_ci }); 13531cb0ef41Sopenharmony_ci rl.on('close', common.mustCall()); 13541cb0ef41Sopenharmony_ci assert.strictEqual(getEventListeners(signal, 'abort').length, 0); 13551cb0ef41Sopenharmony_ci} 13561cb0ef41Sopenharmony_ci 13571cb0ef41Sopenharmony_ci{ 13581cb0ef41Sopenharmony_ci const fi = new FakeInput(); 13591cb0ef41Sopenharmony_ci const ac = new AbortController(); 13601cb0ef41Sopenharmony_ci const { signal } = ac; 13611cb0ef41Sopenharmony_ci const rl = readline.createInterface({ 13621cb0ef41Sopenharmony_ci input: fi, 13631cb0ef41Sopenharmony_ci output: fi, 13641cb0ef41Sopenharmony_ci signal, 13651cb0ef41Sopenharmony_ci }); 13661cb0ef41Sopenharmony_ci assert.strictEqual(getEventListeners(signal, 'abort').length, 1); 13671cb0ef41Sopenharmony_ci rl.on('close', common.mustCall()); 13681cb0ef41Sopenharmony_ci ac.abort(); 13691cb0ef41Sopenharmony_ci assert.strictEqual(getEventListeners(signal, 'abort').length, 0); 13701cb0ef41Sopenharmony_ci} 13711cb0ef41Sopenharmony_ci 13721cb0ef41Sopenharmony_ci{ 13731cb0ef41Sopenharmony_ci const fi = new FakeInput(); 13741cb0ef41Sopenharmony_ci const ac = new AbortController(); 13751cb0ef41Sopenharmony_ci const { signal } = ac; 13761cb0ef41Sopenharmony_ci const rl = readline.createInterface({ 13771cb0ef41Sopenharmony_ci input: fi, 13781cb0ef41Sopenharmony_ci output: fi, 13791cb0ef41Sopenharmony_ci signal, 13801cb0ef41Sopenharmony_ci }); 13811cb0ef41Sopenharmony_ci assert.strictEqual(getEventListeners(signal, 'abort').length, 1); 13821cb0ef41Sopenharmony_ci rl.close(); 13831cb0ef41Sopenharmony_ci assert.strictEqual(getEventListeners(signal, 'abort').length, 0); 13841cb0ef41Sopenharmony_ci} 13851cb0ef41Sopenharmony_ci 13861cb0ef41Sopenharmony_ci{ 13871cb0ef41Sopenharmony_ci // Constructor throws if signal is not an abort signal 13881cb0ef41Sopenharmony_ci assert.throws(() => { 13891cb0ef41Sopenharmony_ci readline.createInterface({ 13901cb0ef41Sopenharmony_ci input: new FakeInput(), 13911cb0ef41Sopenharmony_ci signal: {}, 13921cb0ef41Sopenharmony_ci }); 13931cb0ef41Sopenharmony_ci }, { 13941cb0ef41Sopenharmony_ci name: 'TypeError', 13951cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_TYPE' 13961cb0ef41Sopenharmony_ci }); 13971cb0ef41Sopenharmony_ci} 1398