11cb0ef41Sopenharmony_ci// Flags: --expose-internals 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci// This tests Node.js-specific behaviors of TextDecoder 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci'use strict'; 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciconst common = require('../common'); 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciconst assert = require('assert'); 101cb0ef41Sopenharmony_ciconst { customInspectSymbol: inspect } = require('internal/util'); 111cb0ef41Sopenharmony_ciconst util = require('util'); 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ciconst buf = Buffer.from([0xef, 0xbb, 0xbf, 0x74, 0x65, 141cb0ef41Sopenharmony_ci 0x73, 0x74, 0xe2, 0x82, 0xac]); 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ci// Make Sure TextDecoder exist 171cb0ef41Sopenharmony_ciassert(TextDecoder); 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci// Test TextDecoder, UTF-8, fatal: false, ignoreBOM: false 201cb0ef41Sopenharmony_ci{ 211cb0ef41Sopenharmony_ci ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => { 221cb0ef41Sopenharmony_ci const dec = new TextDecoder(i); 231cb0ef41Sopenharmony_ci assert.strictEqual(dec.encoding, 'utf-8'); 241cb0ef41Sopenharmony_ci const res = dec.decode(buf); 251cb0ef41Sopenharmony_ci assert.strictEqual(res, 'test€'); 261cb0ef41Sopenharmony_ci }); 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => { 291cb0ef41Sopenharmony_ci const dec = new TextDecoder(i); 301cb0ef41Sopenharmony_ci let res = ''; 311cb0ef41Sopenharmony_ci res += dec.decode(buf.slice(0, 8), { stream: true }); 321cb0ef41Sopenharmony_ci res += dec.decode(buf.slice(8)); 331cb0ef41Sopenharmony_ci assert.strictEqual(res, 'test€'); 341cb0ef41Sopenharmony_ci }); 351cb0ef41Sopenharmony_ci} 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci// Test TextDecoder, UTF-8, fatal: false, ignoreBOM: true 381cb0ef41Sopenharmony_ci{ 391cb0ef41Sopenharmony_ci ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => { 401cb0ef41Sopenharmony_ci const dec = new TextDecoder(i, { ignoreBOM: true }); 411cb0ef41Sopenharmony_ci const res = dec.decode(buf); 421cb0ef41Sopenharmony_ci assert.strictEqual(res, '\ufefftest€'); 431cb0ef41Sopenharmony_ci }); 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => { 461cb0ef41Sopenharmony_ci const dec = new TextDecoder(i, { ignoreBOM: true }); 471cb0ef41Sopenharmony_ci let res = ''; 481cb0ef41Sopenharmony_ci res += dec.decode(buf.slice(0, 8), { stream: true }); 491cb0ef41Sopenharmony_ci res += dec.decode(buf.slice(8)); 501cb0ef41Sopenharmony_ci assert.strictEqual(res, '\ufefftest€'); 511cb0ef41Sopenharmony_ci }); 521cb0ef41Sopenharmony_ci} 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci// Invalid encoders 551cb0ef41Sopenharmony_ci{ 561cb0ef41Sopenharmony_ci ['meow', 'nonunicode', 'foo', 'bar'].forEach((fakeEncoding) => { 571cb0ef41Sopenharmony_ci assert.throws( 581cb0ef41Sopenharmony_ci () => { new TextDecoder(fakeEncoding); }, 591cb0ef41Sopenharmony_ci { 601cb0ef41Sopenharmony_ci code: 'ERR_ENCODING_NOT_SUPPORTED', 611cb0ef41Sopenharmony_ci name: 'RangeError' 621cb0ef41Sopenharmony_ci } 631cb0ef41Sopenharmony_ci ); 641cb0ef41Sopenharmony_ci }); 651cb0ef41Sopenharmony_ci} 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci// Test TextDecoder, UTF-8, fatal: true, ignoreBOM: false 681cb0ef41Sopenharmony_ciif (common.hasIntl) { 691cb0ef41Sopenharmony_ci ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => { 701cb0ef41Sopenharmony_ci const dec = new TextDecoder(i, { fatal: true }); 711cb0ef41Sopenharmony_ci assert.throws(() => dec.decode(buf.slice(0, 8)), 721cb0ef41Sopenharmony_ci { 731cb0ef41Sopenharmony_ci code: 'ERR_ENCODING_INVALID_ENCODED_DATA', 741cb0ef41Sopenharmony_ci name: 'TypeError', 751cb0ef41Sopenharmony_ci message: 'The encoded data was not valid ' + 761cb0ef41Sopenharmony_ci 'for encoding utf-8' 771cb0ef41Sopenharmony_ci }); 781cb0ef41Sopenharmony_ci }); 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci ['unicode-1-1-utf-8', 'utf8', 'utf-8'].forEach((i) => { 811cb0ef41Sopenharmony_ci const dec = new TextDecoder(i, { fatal: true }); 821cb0ef41Sopenharmony_ci dec.decode(buf.slice(0, 8), { stream: true }); 831cb0ef41Sopenharmony_ci dec.decode(buf.slice(8)); 841cb0ef41Sopenharmony_ci }); 851cb0ef41Sopenharmony_ci} else { 861cb0ef41Sopenharmony_ci assert.throws( 871cb0ef41Sopenharmony_ci () => new TextDecoder('utf-8', { fatal: true }), 881cb0ef41Sopenharmony_ci { 891cb0ef41Sopenharmony_ci code: 'ERR_NO_ICU', 901cb0ef41Sopenharmony_ci name: 'TypeError', 911cb0ef41Sopenharmony_ci message: '"fatal" option is not supported on Node.js compiled without ICU' 921cb0ef41Sopenharmony_ci }); 931cb0ef41Sopenharmony_ci} 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci// Test TextDecoder, label undefined, options null 961cb0ef41Sopenharmony_ci{ 971cb0ef41Sopenharmony_ci const dec = new TextDecoder(undefined, null); 981cb0ef41Sopenharmony_ci assert.strictEqual(dec.encoding, 'utf-8'); 991cb0ef41Sopenharmony_ci assert.strictEqual(dec.fatal, false); 1001cb0ef41Sopenharmony_ci assert.strictEqual(dec.ignoreBOM, false); 1011cb0ef41Sopenharmony_ci assert.strictEqual(dec[Symbol.toStringTag], 'TextDecoder'); 1021cb0ef41Sopenharmony_ci} 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci// Test TextDecoder, UTF-16le 1051cb0ef41Sopenharmony_ci{ 1061cb0ef41Sopenharmony_ci const dec = new TextDecoder('utf-16le'); 1071cb0ef41Sopenharmony_ci const res = dec.decode(Buffer.from('test€', 'utf-16le')); 1081cb0ef41Sopenharmony_ci assert.strictEqual(res, 'test€'); 1091cb0ef41Sopenharmony_ci} 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci// Test TextDecoder, UTF-16be 1121cb0ef41Sopenharmony_ciif (common.hasIntl) { 1131cb0ef41Sopenharmony_ci const dec = new TextDecoder('utf-16be'); 1141cb0ef41Sopenharmony_ci const res = dec.decode(Buffer.from('test€', 'utf-16le').swap16()); 1151cb0ef41Sopenharmony_ci assert.strictEqual(res, 'test€'); 1161cb0ef41Sopenharmony_ci} 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci// Test TextDecoder inspect with hidden fields 1191cb0ef41Sopenharmony_ci{ 1201cb0ef41Sopenharmony_ci const dec = new TextDecoder('utf-8', { ignoreBOM: true }); 1211cb0ef41Sopenharmony_ci if (common.hasIntl) { 1221cb0ef41Sopenharmony_ci assert.strictEqual( 1231cb0ef41Sopenharmony_ci util.inspect(dec, { showHidden: true }), 1241cb0ef41Sopenharmony_ci 'TextDecoder {\n' + 1251cb0ef41Sopenharmony_ci ' encoding: \'utf-8\',\n' + 1261cb0ef41Sopenharmony_ci ' fatal: false,\n' + 1271cb0ef41Sopenharmony_ci ' ignoreBOM: true,\n' + 1281cb0ef41Sopenharmony_ci ' [Symbol(flags)]: 4,\n' + 1291cb0ef41Sopenharmony_ci ' [Symbol(handle)]: undefined\n' + 1301cb0ef41Sopenharmony_ci '}' 1311cb0ef41Sopenharmony_ci ); 1321cb0ef41Sopenharmony_ci } else { 1331cb0ef41Sopenharmony_ci assert.strictEqual( 1341cb0ef41Sopenharmony_ci util.inspect(dec, { showHidden: true }), 1351cb0ef41Sopenharmony_ci 'TextDecoder {\n' + 1361cb0ef41Sopenharmony_ci " encoding: 'utf-8',\n" + 1371cb0ef41Sopenharmony_ci ' fatal: false,\n' + 1381cb0ef41Sopenharmony_ci ' ignoreBOM: true,\n' + 1391cb0ef41Sopenharmony_ci ' [Symbol(flags)]: 4,\n' + 1401cb0ef41Sopenharmony_ci ' [Symbol(handle)]: StringDecoder {\n' + 1411cb0ef41Sopenharmony_ci " encoding: 'utf8',\n" + 1421cb0ef41Sopenharmony_ci ' [Symbol(kNativeDecoder)]: <Buffer 00 00 00 00 00 00 01>\n' + 1431cb0ef41Sopenharmony_ci ' }\n' + 1441cb0ef41Sopenharmony_ci '}' 1451cb0ef41Sopenharmony_ci ); 1461cb0ef41Sopenharmony_ci } 1471cb0ef41Sopenharmony_ci} 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci// Test TextDecoder inspect without hidden fields 1511cb0ef41Sopenharmony_ci{ 1521cb0ef41Sopenharmony_ci const dec = new TextDecoder('utf-8', { ignoreBOM: true }); 1531cb0ef41Sopenharmony_ci assert.strictEqual( 1541cb0ef41Sopenharmony_ci util.inspect(dec, { showHidden: false }), 1551cb0ef41Sopenharmony_ci 'TextDecoder { encoding: \'utf-8\', fatal: false, ignoreBOM: true }' 1561cb0ef41Sopenharmony_ci ); 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci// Test TextDecoder inspect with negative depth 1601cb0ef41Sopenharmony_ci{ 1611cb0ef41Sopenharmony_ci const dec = new TextDecoder(); 1621cb0ef41Sopenharmony_ci assert.strictEqual(util.inspect(dec, { depth: -1 }), '[TextDecoder]'); 1631cb0ef41Sopenharmony_ci} 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci{ 1661cb0ef41Sopenharmony_ci const inspectFn = TextDecoder.prototype[inspect]; 1671cb0ef41Sopenharmony_ci const decodeFn = TextDecoder.prototype.decode; 1681cb0ef41Sopenharmony_ci const { 1691cb0ef41Sopenharmony_ci encoding: { get: encodingGetter }, 1701cb0ef41Sopenharmony_ci fatal: { get: fatalGetter }, 1711cb0ef41Sopenharmony_ci ignoreBOM: { get: ignoreBOMGetter }, 1721cb0ef41Sopenharmony_ci } = Object.getOwnPropertyDescriptors(TextDecoder.prototype); 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci const instance = new TextDecoder(); 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci const expectedError = { 1771cb0ef41Sopenharmony_ci code: 'ERR_INVALID_THIS', 1781cb0ef41Sopenharmony_ci name: 'TypeError', 1791cb0ef41Sopenharmony_ci message: 'Value of "this" must be of type TextDecoder' 1801cb0ef41Sopenharmony_ci }; 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci inspectFn.call(instance, Infinity, {}); 1831cb0ef41Sopenharmony_ci decodeFn.call(instance); 1841cb0ef41Sopenharmony_ci encodingGetter.call(instance); 1851cb0ef41Sopenharmony_ci fatalGetter.call(instance); 1861cb0ef41Sopenharmony_ci ignoreBOMGetter.call(instance); 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci const invalidThisArgs = [{}, [], true, 1, '', new TextEncoder()]; 1891cb0ef41Sopenharmony_ci invalidThisArgs.forEach((i) => { 1901cb0ef41Sopenharmony_ci assert.throws(() => inspectFn.call(i, Infinity, {}), expectedError); 1911cb0ef41Sopenharmony_ci assert.throws(() => decodeFn.call(i), expectedError); 1921cb0ef41Sopenharmony_ci assert.throws(() => encodingGetter.call(i), expectedError); 1931cb0ef41Sopenharmony_ci assert.throws(() => fatalGetter.call(i), expectedError); 1941cb0ef41Sopenharmony_ci assert.throws(() => ignoreBOMGetter.call(i), expectedError); 1951cb0ef41Sopenharmony_ci }); 1961cb0ef41Sopenharmony_ci} 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci{ 1991cb0ef41Sopenharmony_ci assert.throws( 2001cb0ef41Sopenharmony_ci () => new TextDecoder('utf-8', 1), 2011cb0ef41Sopenharmony_ci { 2021cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_TYPE', 2031cb0ef41Sopenharmony_ci name: 'TypeError' 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci ); 2061cb0ef41Sopenharmony_ci} 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci// Test TextDecoder for incomplete UTF-8 byte sequence. 2091cb0ef41Sopenharmony_ci{ 2101cb0ef41Sopenharmony_ci const decoder = new TextDecoder(); 2111cb0ef41Sopenharmony_ci const chunk = new Uint8Array([0x66, 0x6f, 0x6f, 0xed]); 2121cb0ef41Sopenharmony_ci const str = decoder.decode(chunk); 2131cb0ef41Sopenharmony_ci assert.strictEqual(str, 'foo\ufffd'); 2141cb0ef41Sopenharmony_ci} 2151cb0ef41Sopenharmony_ci 2161cb0ef41Sopenharmony_ciif (common.hasIntl) { 2171cb0ef41Sopenharmony_ci try { 2181cb0ef41Sopenharmony_ci const decoder = new TextDecoder('Shift_JIS'); 2191cb0ef41Sopenharmony_ci const chunk = new Uint8Array([-1]); 2201cb0ef41Sopenharmony_ci const str = decoder.decode(chunk); 2211cb0ef41Sopenharmony_ci assert.strictEqual(str, '\ufffd'); 2221cb0ef41Sopenharmony_ci } catch (e) { 2231cb0ef41Sopenharmony_ci // Encoding may not be available, e.g. small-icu builds 2241cb0ef41Sopenharmony_ci assert.strictEqual(e.code, 'ERR_ENCODING_NOT_SUPPORTED'); 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci} 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ci{ 2291cb0ef41Sopenharmony_ci const buffer = new ArrayBuffer(1); 2301cb0ef41Sopenharmony_ci new MessageChannel().port1.postMessage(buffer, [buffer]); // buffer is detached 2311cb0ef41Sopenharmony_ci const decoder = new TextDecoder(); 2321cb0ef41Sopenharmony_ci assert.strictEqual(decoder.decode(buffer), ''); 2331cb0ef41Sopenharmony_ci} 234