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} 89 90// Test TextDecoder, UTF-16le 91{ 92 const dec = new TextDecoder('utf-16le'); 93 const res = dec.decode(Buffer.from('test€', 'utf-16le')); 94 assert.strictEqual(res, 'test€'); 95} 96 97// Test TextDecoder, UTF-16be 98if (common.hasIntl) { 99 const dec = new TextDecoder('utf-16be'); 100 const res = dec.decode(Buffer.from('test€', 'utf-16le').swap16()); 101 assert.strictEqual(res, 'test€'); 102} 103 104// Test TextDecoder inspect with hidden fields 105{ 106 const dec = new TextDecoder('utf-8', { ignoreBOM: true }); 107 if (common.hasIntl) { 108 assert.strictEqual( 109 util.inspect(dec, { showHidden: true }), 110 'TextDecoder {\n' + 111 ' encoding: \'utf-8\',\n' + 112 ' fatal: false,\n' + 113 ' ignoreBOM: true,\n' + 114 ' [Symbol(flags)]: 4,\n' + 115 ' [Symbol(handle)]: Converter {}\n' + 116 '}' 117 ); 118 } else { 119 assert.strictEqual( 120 util.inspect(dec, { showHidden: true }), 121 'TextDecoder {\n' + 122 " encoding: 'utf-8',\n" + 123 ' fatal: false,\n' + 124 ' ignoreBOM: true,\n' + 125 ' [Symbol(flags)]: 4,\n' + 126 ' [Symbol(handle)]: StringDecoder {\n' + 127 " encoding: 'utf8',\n" + 128 ' [Symbol(kNativeDecoder)]: <Buffer 00 00 00 00 00 00 01>,\n' + 129 ' lastChar: [Getter],\n' + 130 ' lastNeed: [Getter],\n' + 131 ' lastTotal: [Getter]\n' + 132 ' }\n' + 133 '}' 134 ); 135 } 136} 137 138 139// Test TextDecoder inspect without hidden fields 140{ 141 const dec = new TextDecoder('utf-8', { ignoreBOM: true }); 142 assert.strictEqual( 143 util.inspect(dec, { showHidden: false }), 144 'TextDecoder { encoding: \'utf-8\', fatal: false, ignoreBOM: true }' 145 ); 146} 147 148// Test TextDecoder inspect with negative depth 149{ 150 const dec = new TextDecoder(); 151 assert.strictEqual(util.inspect(dec, { depth: -1 }), '[TextDecoder]'); 152} 153 154{ 155 const inspectFn = TextDecoder.prototype[inspect]; 156 const decodeFn = TextDecoder.prototype.decode; 157 const { 158 encoding: { get: encodingGetter }, 159 fatal: { get: fatalGetter }, 160 ignoreBOM: { get: ignoreBOMGetter }, 161 } = Object.getOwnPropertyDescriptors(TextDecoder.prototype); 162 163 const instance = new TextDecoder(); 164 165 const expectedError = { 166 code: 'ERR_INVALID_THIS', 167 name: 'TypeError', 168 message: 'Value of "this" must be of type TextDecoder' 169 }; 170 171 inspectFn.call(instance, Infinity, {}); 172 decodeFn.call(instance); 173 encodingGetter.call(instance); 174 fatalGetter.call(instance); 175 ignoreBOMGetter.call(instance); 176 177 const invalidThisArgs = [{}, [], true, 1, '', new TextEncoder()]; 178 invalidThisArgs.forEach((i) => { 179 assert.throws(() => inspectFn.call(i, Infinity, {}), expectedError); 180 assert.throws(() => decodeFn.call(i), expectedError); 181 assert.throws(() => encodingGetter.call(i), expectedError); 182 assert.throws(() => fatalGetter.call(i), expectedError); 183 assert.throws(() => ignoreBOMGetter.call(i), expectedError); 184 }); 185} 186 187{ 188 assert.throws( 189 () => new TextDecoder('utf-8', 1), 190 { 191 code: 'ERR_INVALID_ARG_TYPE', 192 name: 'TypeError' 193 } 194 ); 195} 196