1'use strict';
2
3// Flags: --expose-internals
4
5const common = require('../common');
6const readline = require('readline/promises');
7const assert = require('assert');
8const { EventEmitter } = require('events');
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    [
22      (line) => [
23        ['First group', '',
24         `${char}${'a'.repeat(10)}`,
25         `${char}${'b'.repeat(10)}`,
26         char.repeat(11),
27        ],
28        line,
29      ],
30
31      async (line) => [
32        ['First group', '',
33         `${char}${'a'.repeat(10)}`,
34         `${char}${'b'.repeat(10)}`,
35         char.repeat(11),
36        ],
37        line,
38      ],
39    ].forEach((completer) => {
40
41      let output = '';
42      const width = getStringWidth(char) - 1;
43
44      class FakeInput extends EventEmitter {
45        columns = ((width + 1) * 10 + (lineBreak ? 0 : 10)) * 3;
46
47        write = common.mustCall((data) => {
48          output += data;
49        }, 6);
50
51        resume() {}
52        pause() {}
53        end() {}
54      }
55
56      const fi = new FakeInput();
57      const rli = new readline.Interface({
58        input: fi,
59        output: fi,
60        terminal: true,
61        completer: common.mustCallAtLeast(completer),
62      });
63
64      const last = '\r\nFirst group\r\n\r\n' +
65        `${char}${'a'.repeat(10)}${' '.repeat(2 + width * 10)}` +
66        `${char}${'b'.repeat(10)}` +
67        (lineBreak ? '\r\n' : ' '.repeat(2 + width * 10)) +
68        `${char.repeat(11)}\r\n` +
69        `\r\n\u001b[1G\u001b[0J> ${char}\u001b[${4 + width}G`;
70
71      const expectations = [char, '', last];
72
73      rli.on('line', common.mustNotCall());
74      for (const character of `${char}\t\t`) {
75        fi.emit('data', character);
76        queueMicrotask(() => {
77          assert.strictEqual(output, expectations.shift());
78          output = '';
79        });
80      }
81      rli.close();
82    });
83  });
84});
85
86{
87  let output = '';
88  class FakeInput extends EventEmitter {
89    columns = 80;
90
91    write = common.mustCall((data) => {
92      output += data;
93    }, 1);
94
95    resume() {}
96    pause() {}
97    end() {}
98  }
99
100  const fi = new FakeInput();
101  const rli = new readline.Interface({
102    input: fi,
103    output: fi,
104    terminal: true,
105    completer:
106        common.mustCallAtLeast(() => Promise.reject(new Error('message'))),
107  });
108
109  rli.on('line', common.mustNotCall());
110  fi.emit('data', '\t');
111  queueMicrotask(() => {
112    assert.match(output, /^Tab completion error: Error: message/);
113    output = '';
114  });
115  rli.close();
116}
117