1'use strict'; 2 3// Flags: --expose-internals 4 5const common = require('../common'); 6const readline = require('readline'); 7const assert = require('assert'); 8const EventEmitter = require('events').EventEmitter; 9const { getStringWidth } = require('internal/util/inspect'); 10 11common.skipIfDumbTerminal(); 12 13// This test verifies that the tab completion supports unicode and the writes 14// are limited to the minimum. 15[ 16 'あ', 17 '', 18 '', 19].forEach((char) => { 20 [true, false].forEach((lineBreak) => { 21 const completer = (line) => [ 22 [ 23 'First group', 24 '', 25 `${char}${'a'.repeat(10)}`, `${char}${'b'.repeat(10)}`, char.repeat(11), 26 ], 27 line, 28 ]; 29 30 let output = ''; 31 const width = getStringWidth(char) - 1; 32 33 class FakeInput extends EventEmitter { 34 columns = ((width + 1) * 10 + (lineBreak ? 0 : 10)) * 3; 35 36 write = common.mustCall((data) => { 37 output += data; 38 }, 6); 39 40 resume() {} 41 pause() {} 42 end() {} 43 } 44 45 const fi = new FakeInput(); 46 const rli = new readline.Interface({ 47 input: fi, 48 output: fi, 49 terminal: true, 50 completer: common.mustCallAtLeast(completer), 51 }); 52 53 const last = '\r\nFirst group\r\n\r\n' + 54 `${char}${'a'.repeat(10)}${' '.repeat(2 + width * 10)}` + 55 `${char}${'b'.repeat(10)}` + 56 (lineBreak ? '\r\n' : ' '.repeat(2 + width * 10)) + 57 `${char.repeat(11)}\r\n` + 58 `\r\n\u001b[1G\u001b[0J> ${char}\u001b[${4 + width}G`; 59 60 const expectations = [char, '', last]; 61 62 rli.on('line', common.mustNotCall()); 63 for (const character of `${char}\t\t`) { 64 fi.emit('data', character); 65 assert.strictEqual(output, expectations.shift()); 66 output = ''; 67 } 68 rli.close(); 69 }); 70}); 71 72{ 73 let output = ''; 74 class FakeInput extends EventEmitter { 75 columns = 80; 76 77 write = common.mustCall((data) => { 78 output += data; 79 }, 1); 80 81 resume() {} 82 pause() {} 83 end() {} 84 } 85 86 const fi = new FakeInput(); 87 const rli = new readline.Interface({ 88 input: fi, 89 output: fi, 90 terminal: true, 91 completer: 92 common.mustCallAtLeast((_, cb) => cb(new Error('message'))), 93 }); 94 95 rli.on('line', common.mustNotCall()); 96 fi.emit('data', '\t'); 97 queueMicrotask(() => { 98 assert.match(output, /^Tab completion error: Error: message/); 99 output = ''; 100 }); 101 rli.close(); 102} 103 104{ 105 let output = ''; 106 class FakeInput extends EventEmitter { 107 columns = 80; 108 109 write = common.mustCall((data) => { 110 output += data; 111 }, 9); 112 113 resume() {} 114 pause() {} 115 end() {} 116 } 117 118 const fi = new FakeInput(); 119 const rli = new readline.Interface({ 120 input: fi, 121 output: fi, 122 terminal: true, 123 completer: common.mustCall((input, cb) => { 124 cb(null, [[input[0].toUpperCase() + input.slice(1)], input]); 125 }), 126 }); 127 128 rli.on('line', common.mustNotCall()); 129 fi.emit('data', 'input'); 130 queueMicrotask(() => { 131 fi.emit('data', '\t'); 132 queueMicrotask(() => { 133 assert.match(output, /> Input/); 134 output = ''; 135 rli.close(); 136 }); 137 }); 138} 139