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