• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Flags: --expose-internals
2
3// This tests Node.js-specific behaviors of TextDecoder
4
5'use strict';
6
7const common = require('../common');
8
9const assert = require('assert');
10const { customInspectSymbol: inspect } = require('internal/util');
11const util = require('util');
12
13const buf = Buffer.from([0xef, 0xbb, 0xbf, 0x74, 0x65,
14                         0x73, 0x74, 0xe2, 0x82, 0xac]);
15
16// Make Sure TextDecoder exist
17assert(TextDecoder);
18
19// Test TextDecoder, UTF-8, fatal: false, ignoreBOM: false
20{
21  ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => {
22    const dec = new TextDecoder(i);
23    assert.strictEqual(dec.encoding, 'utf-8');
24    const res = dec.decode(buf);
25    assert.strictEqual(res, 'test€');
26  });
27
28  ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => {
29    const dec = new TextDecoder(i);
30    let res = '';
31    res += dec.decode(buf.slice(0, 8), { stream: true });
32    res += dec.decode(buf.slice(8));
33    assert.strictEqual(res, 'test€');
34  });
35}
36
37// Test TextDecoder, UTF-8, fatal: false, ignoreBOM: true
38{
39  ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => {
40    const dec = new TextDecoder(i, { ignoreBOM: true });
41    const res = dec.decode(buf);
42    assert.strictEqual(res, '\ufefftest€');
43  });
44
45  ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => {
46    const dec = new TextDecoder(i, { ignoreBOM: true });
47    let res = '';
48    res += dec.decode(buf.slice(0, 8), { stream: true });
49    res += dec.decode(buf.slice(8));
50    assert.strictEqual(res, '\ufefftest€');
51  });
52}
53
54// Test TextDecoder, UTF-8, fatal: true, ignoreBOM: false
55if (common.hasIntl) {
56  ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => {
57    const dec = new TextDecoder(i, { fatal: true });
58    assert.throws(() => dec.decode(buf.slice(0, 8)),
59                  {
60                    code: 'ERR_ENCODING_INVALID_ENCODED_DATA',
61                    name: 'TypeError',
62                    message: 'The encoded data was not valid ' +
63                          'for encoding utf-8'
64                  });
65  });
66
67  ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => {
68    const dec = new TextDecoder(i, { fatal: true });
69    dec.decode(buf.slice(0, 8), { stream: true });
70    dec.decode(buf.slice(8));
71  });
72} else {
73  assert.throws(
74    () => new TextDecoder('utf-8', { fatal: true }),
75    {
76      code: 'ERR_NO_ICU',
77      name: 'TypeError',
78      message: '"fatal" option is not supported on Node.js compiled without ICU'
79    });
80}
81
82// Test TextDecoder, label undefined, options null
83{
84  const dec = new TextDecoder(undefined, null);
85  assert.strictEqual(dec.encoding, 'utf-8');
86  assert.strictEqual(dec.fatal, false);
87  assert.strictEqual(dec.ignoreBOM, false);
88  assert.strictEqual(dec[Symbol.toStringTag], 'TextDecoder');
89}
90
91// Test TextDecoder, UTF-16le
92{
93  const dec = new TextDecoder('utf-16le');
94  const res = dec.decode(Buffer.from('test€', 'utf-16le'));
95  assert.strictEqual(res, 'test€');
96}
97
98// Test TextDecoder, UTF-16be
99if (common.hasIntl) {
100  const dec = new TextDecoder('utf-16be');
101  const res = dec.decode(Buffer.from('test€', 'utf-16le').swap16());
102  assert.strictEqual(res, 'test€');
103}
104
105// Test TextDecoder inspect with hidden fields
106{
107  const dec = new TextDecoder('utf-8', { ignoreBOM: true });
108  if (common.hasIntl) {
109    assert.strictEqual(
110      util.inspect(dec, { showHidden: true }),
111      'TextDecoder {\n' +
112      '  encoding: \'utf-8\',\n' +
113      '  fatal: false,\n' +
114      '  ignoreBOM: true,\n' +
115      '  [Symbol(flags)]: 4,\n' +
116      '  [Symbol(handle)]: Converter {}\n' +
117      '}'
118    );
119  } else {
120    assert.strictEqual(
121      util.inspect(dec, { showHidden: true }),
122      'TextDecoder {\n' +
123      "  encoding: 'utf-8',\n" +
124      '  fatal: false,\n' +
125      '  ignoreBOM: true,\n' +
126      '  [Symbol(flags)]: 4,\n' +
127      '  [Symbol(handle)]: StringDecoder {\n' +
128      "    encoding: 'utf8',\n" +
129      '    [Symbol(kNativeDecoder)]: <Buffer 00 00 00 00 00 00 01>\n' +
130      '  }\n' +
131      '}'
132    );
133  }
134}
135
136
137// Test TextDecoder inspect without hidden fields
138{
139  const dec = new TextDecoder('utf-8', { ignoreBOM: true });
140  assert.strictEqual(
141    util.inspect(dec, { showHidden: false }),
142    'TextDecoder { encoding: \'utf-8\', fatal: false, ignoreBOM: true }'
143  );
144}
145
146// Test TextDecoder inspect with negative depth
147{
148  const dec = new TextDecoder();
149  assert.strictEqual(util.inspect(dec, { depth: -1 }), '[TextDecoder]');
150}
151
152{
153  const inspectFn = TextDecoder.prototype[inspect];
154  const decodeFn = TextDecoder.prototype.decode;
155  const {
156    encoding: { get: encodingGetter },
157    fatal: { get: fatalGetter },
158    ignoreBOM: { get: ignoreBOMGetter },
159  } = Object.getOwnPropertyDescriptors(TextDecoder.prototype);
160
161  const instance = new TextDecoder();
162
163  const expectedError = {
164    code: 'ERR_INVALID_THIS',
165    name: 'TypeError',
166    message: 'Value of "this" must be of type TextDecoder'
167  };
168
169  inspectFn.call(instance, Infinity, {});
170  decodeFn.call(instance);
171  encodingGetter.call(instance);
172  fatalGetter.call(instance);
173  ignoreBOMGetter.call(instance);
174
175  const invalidThisArgs = [{}, [], true, 1, '', new TextEncoder()];
176  invalidThisArgs.forEach((i) => {
177    assert.throws(() => inspectFn.call(i, Infinity, {}), expectedError);
178    assert.throws(() => decodeFn.call(i), expectedError);
179    assert.throws(() => encodingGetter.call(i), expectedError);
180    assert.throws(() => fatalGetter.call(i), expectedError);
181    assert.throws(() => ignoreBOMGetter.call(i), expectedError);
182  });
183}
184
185{
186  assert.throws(
187    () => new TextDecoder('utf-8', 1),
188    {
189      code: 'ERR_INVALID_ARG_TYPE',
190      name: 'TypeError'
191    }
192  );
193}
194