• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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