Path: blob/main/src/vs/base/test/common/buffer.test.ts
5221 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { timeout } from '../../common/async.js';7import { bufferedStreamToBuffer, bufferToReadable, bufferToStream, decodeBase64, decodeHex, encodeBase64, encodeHex, newWriteableBufferStream, readableToBuffer, streamToBuffer, VSBuffer } from '../../common/buffer.js';8import { peekStream } from '../../common/stream.js';9import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js';1011suite('Buffer', () => {1213ensureNoDisposablesAreLeakedInTestSuite();1415test('issue #71993 - VSBuffer#toString returns numbers', () => {16const data = new Uint8Array([1, 2, 3, 'h'.charCodeAt(0), 'i'.charCodeAt(0), 4, 5]).buffer;17const buffer = VSBuffer.wrap(new Uint8Array(data, 3, 2));18assert.deepStrictEqual(buffer.toString(), 'hi');19});2021test('issue #251527 - VSBuffer#toString preserves BOM character in filenames', () => {22// BOM character (U+FEFF) is a zero-width character that was being stripped23// when deserializing messages in the IPC layer. This test verifies that24// the BOM character is preserved when using VSBuffer.toString().25const bomChar = '\uFEFF';26const filename = `${bomChar}c.txt`;27const buffer = VSBuffer.fromString(filename);28const result = buffer.toString();2930// Verify the BOM character is preserved31assert.strictEqual(result, filename);32assert.strictEqual(result.charCodeAt(0), 0xFEFF);33});3435test('bufferToReadable / readableToBuffer', () => {36const content = 'Hello World';37const readable = bufferToReadable(VSBuffer.fromString(content));3839assert.strictEqual(readableToBuffer(readable).toString(), content);40});4142test('bufferToStream / streamToBuffer', async () => {43const content = 'Hello World';44const stream = bufferToStream(VSBuffer.fromString(content));4546assert.strictEqual((await streamToBuffer(stream)).toString(), content);47});4849test('bufferedStreamToBuffer', async () => {50const content = 'Hello World';51const stream = await peekStream(bufferToStream(VSBuffer.fromString(content)), 1);5253assert.strictEqual((await bufferedStreamToBuffer(stream)).toString(), content);54});5556test('bufferWriteableStream - basics (no error)', async () => {57const stream = newWriteableBufferStream();5859const chunks: VSBuffer[] = [];60stream.on('data', data => {61chunks.push(data);62});6364let ended = false;65stream.on('end', () => {66ended = true;67});6869const errors: Error[] = [];70stream.on('error', error => {71errors.push(error);72});7374await timeout(0);75stream.write(VSBuffer.fromString('Hello'));76await timeout(0);77stream.end(VSBuffer.fromString('World'));7879assert.strictEqual(chunks.length, 2);80assert.strictEqual(chunks[0].toString(), 'Hello');81assert.strictEqual(chunks[1].toString(), 'World');82assert.strictEqual(ended, true);83assert.strictEqual(errors.length, 0);84});8586test('bufferWriteableStream - basics (error)', async () => {87const stream = newWriteableBufferStream();8889const chunks: VSBuffer[] = [];90stream.on('data', data => {91chunks.push(data);92});9394let ended = false;95stream.on('end', () => {96ended = true;97});9899const errors: Error[] = [];100stream.on('error', error => {101errors.push(error);102});103104await timeout(0);105stream.write(VSBuffer.fromString('Hello'));106await timeout(0);107stream.error(new Error());108stream.end();109110assert.strictEqual(chunks.length, 1);111assert.strictEqual(chunks[0].toString(), 'Hello');112assert.strictEqual(ended, true);113assert.strictEqual(errors.length, 1);114});115116test('bufferWriteableStream - buffers data when no listener', async () => {117const stream = newWriteableBufferStream();118119await timeout(0);120stream.write(VSBuffer.fromString('Hello'));121await timeout(0);122stream.end(VSBuffer.fromString('World'));123124const chunks: VSBuffer[] = [];125stream.on('data', data => {126chunks.push(data);127});128129let ended = false;130stream.on('end', () => {131ended = true;132});133134const errors: Error[] = [];135stream.on('error', error => {136errors.push(error);137});138139assert.strictEqual(chunks.length, 1);140assert.strictEqual(chunks[0].toString(), 'HelloWorld');141assert.strictEqual(ended, true);142assert.strictEqual(errors.length, 0);143});144145test('bufferWriteableStream - buffers errors when no listener', async () => {146const stream = newWriteableBufferStream();147148await timeout(0);149stream.write(VSBuffer.fromString('Hello'));150await timeout(0);151stream.error(new Error());152153const chunks: VSBuffer[] = [];154stream.on('data', data => {155chunks.push(data);156});157158const errors: Error[] = [];159stream.on('error', error => {160errors.push(error);161});162163let ended = false;164stream.on('end', () => {165ended = true;166});167168stream.end();169170assert.strictEqual(chunks.length, 1);171assert.strictEqual(chunks[0].toString(), 'Hello');172assert.strictEqual(ended, true);173assert.strictEqual(errors.length, 1);174});175176test('bufferWriteableStream - buffers end when no listener', async () => {177const stream = newWriteableBufferStream();178179await timeout(0);180stream.write(VSBuffer.fromString('Hello'));181await timeout(0);182stream.end(VSBuffer.fromString('World'));183184let ended = false;185stream.on('end', () => {186ended = true;187});188189const chunks: VSBuffer[] = [];190stream.on('data', data => {191chunks.push(data);192});193194const errors: Error[] = [];195stream.on('error', error => {196errors.push(error);197});198199assert.strictEqual(chunks.length, 1);200assert.strictEqual(chunks[0].toString(), 'HelloWorld');201assert.strictEqual(ended, true);202assert.strictEqual(errors.length, 0);203});204205test('bufferWriteableStream - nothing happens after end()', async () => {206const stream = newWriteableBufferStream();207208const chunks: VSBuffer[] = [];209stream.on('data', data => {210chunks.push(data);211});212213await timeout(0);214stream.write(VSBuffer.fromString('Hello'));215await timeout(0);216stream.end(VSBuffer.fromString('World'));217218let dataCalledAfterEnd = false;219stream.on('data', data => {220dataCalledAfterEnd = true;221});222223let errorCalledAfterEnd = false;224stream.on('error', error => {225errorCalledAfterEnd = true;226});227228let endCalledAfterEnd = false;229stream.on('end', () => {230endCalledAfterEnd = true;231});232233await timeout(0);234stream.write(VSBuffer.fromString('Hello'));235await timeout(0);236stream.error(new Error());237await timeout(0);238stream.end(VSBuffer.fromString('World'));239240assert.strictEqual(dataCalledAfterEnd, false);241assert.strictEqual(errorCalledAfterEnd, false);242assert.strictEqual(endCalledAfterEnd, false);243244assert.strictEqual(chunks.length, 2);245assert.strictEqual(chunks[0].toString(), 'Hello');246assert.strictEqual(chunks[1].toString(), 'World');247});248249test('bufferWriteableStream - pause/resume (simple)', async () => {250const stream = newWriteableBufferStream();251252const chunks: VSBuffer[] = [];253stream.on('data', data => {254chunks.push(data);255});256257let ended = false;258stream.on('end', () => {259ended = true;260});261262const errors: Error[] = [];263stream.on('error', error => {264errors.push(error);265});266267stream.pause();268269await timeout(0);270stream.write(VSBuffer.fromString('Hello'));271await timeout(0);272stream.end(VSBuffer.fromString('World'));273274assert.strictEqual(chunks.length, 0);275assert.strictEqual(errors.length, 0);276assert.strictEqual(ended, false);277278stream.resume();279280assert.strictEqual(chunks.length, 1);281assert.strictEqual(chunks[0].toString(), 'HelloWorld');282assert.strictEqual(ended, true);283assert.strictEqual(errors.length, 0);284});285286test('bufferWriteableStream - pause/resume (pause after first write)', async () => {287const stream = newWriteableBufferStream();288289const chunks: VSBuffer[] = [];290stream.on('data', data => {291chunks.push(data);292});293294let ended = false;295stream.on('end', () => {296ended = true;297});298299const errors: Error[] = [];300stream.on('error', error => {301errors.push(error);302});303304await timeout(0);305stream.write(VSBuffer.fromString('Hello'));306307stream.pause();308309await timeout(0);310stream.end(VSBuffer.fromString('World'));311312assert.strictEqual(chunks.length, 1);313assert.strictEqual(chunks[0].toString(), 'Hello');314assert.strictEqual(errors.length, 0);315assert.strictEqual(ended, false);316317stream.resume();318319assert.strictEqual(chunks.length, 2);320assert.strictEqual(chunks[0].toString(), 'Hello');321assert.strictEqual(chunks[1].toString(), 'World');322assert.strictEqual(ended, true);323assert.strictEqual(errors.length, 0);324});325326test('bufferWriteableStream - pause/resume (error)', async () => {327const stream = newWriteableBufferStream();328329const chunks: VSBuffer[] = [];330stream.on('data', data => {331chunks.push(data);332});333334let ended = false;335stream.on('end', () => {336ended = true;337});338339const errors: Error[] = [];340stream.on('error', error => {341errors.push(error);342});343344stream.pause();345346await timeout(0);347stream.write(VSBuffer.fromString('Hello'));348await timeout(0);349stream.error(new Error());350stream.end();351352assert.strictEqual(chunks.length, 0);353assert.strictEqual(ended, false);354assert.strictEqual(errors.length, 0);355356stream.resume();357358assert.strictEqual(chunks.length, 1);359assert.strictEqual(chunks[0].toString(), 'Hello');360assert.strictEqual(ended, true);361assert.strictEqual(errors.length, 1);362});363364test('bufferWriteableStream - destroy', async () => {365const stream = newWriteableBufferStream();366367const chunks: VSBuffer[] = [];368stream.on('data', data => {369chunks.push(data);370});371372let ended = false;373stream.on('end', () => {374ended = true;375});376377const errors: Error[] = [];378stream.on('error', error => {379errors.push(error);380});381382stream.destroy();383384await timeout(0);385stream.write(VSBuffer.fromString('Hello'));386await timeout(0);387stream.end(VSBuffer.fromString('World'));388389assert.strictEqual(chunks.length, 0);390assert.strictEqual(ended, false);391assert.strictEqual(errors.length, 0);392});393394test('Performance issue with VSBuffer#slice #76076', function () { // TODO@alexdima this test seems to fail in web (https://github.com/microsoft/vscode/issues/114042)395// Buffer#slice creates a view396if (typeof Buffer !== 'undefined') {397const buff = Buffer.from([10, 20, 30, 40]);398const b2 = buff.slice(1, 3);399assert.strictEqual(buff[1], 20);400assert.strictEqual(b2[0], 20);401402buff[1] = 17; // modify buff AND b2403assert.strictEqual(buff[1], 17);404assert.strictEqual(b2[0], 17);405}406407// TypedArray#slice creates a copy408{409const unit = new Uint8Array([10, 20, 30, 40]);410const u2 = unit.slice(1, 3);411assert.strictEqual(unit[1], 20);412assert.strictEqual(u2[0], 20);413414unit[1] = 17; // modify unit, NOT b2415assert.strictEqual(unit[1], 17);416assert.strictEqual(u2[0], 20);417}418419// TypedArray#subarray creates a view420{421const unit = new Uint8Array([10, 20, 30, 40]);422const u2 = unit.subarray(1, 3);423assert.strictEqual(unit[1], 20);424assert.strictEqual(u2[0], 20);425426unit[1] = 17; // modify unit AND b2427assert.strictEqual(unit[1], 17);428assert.strictEqual(u2[0], 17);429}430});431432test('indexOf', () => {433const haystack = VSBuffer.fromString('abcaabbccaaabbbccc');434assert.strictEqual(haystack.indexOf(VSBuffer.fromString('')), 0);435assert.strictEqual(haystack.indexOf(VSBuffer.fromString('a'.repeat(100))), -1);436437assert.strictEqual(haystack.indexOf(VSBuffer.fromString('a')), 0);438assert.strictEqual(haystack.indexOf(VSBuffer.fromString('c')), 2);439assert.strictEqual(haystack.indexOf(VSBuffer.fromString('c'), 4), 7);440441assert.strictEqual(haystack.indexOf(VSBuffer.fromString('abcaa')), 0);442assert.strictEqual(haystack.indexOf(VSBuffer.fromString('caaab')), 8);443assert.strictEqual(haystack.indexOf(VSBuffer.fromString('ccc')), 15);444assert.strictEqual(haystack.indexOf(VSBuffer.fromString('cc'), 9), 15);445446assert.strictEqual(haystack.indexOf(VSBuffer.fromString('cccb')), -1);447});448449test('wrap', () => {450const actual = new Uint8Array([1, 2, 3]);451const wrapped = VSBuffer.wrap(actual);452assert.strictEqual(wrapped.byteLength, 3);453assert.deepStrictEqual(Array.from(wrapped.buffer), [1, 2, 3]);454});455456test('fromString', () => {457const value = 'Hello World';458const buff = VSBuffer.fromString(value);459assert.strictEqual(buff.toString(), value);460});461462test('fromByteArray', () => {463const array = [1, 2, 3, 4, 5];464const buff = VSBuffer.fromByteArray(array);465assert.strictEqual(buff.byteLength, array.length);466assert.deepStrictEqual(Array.from(buff.buffer), array);467});468469test('concat', () => {470const chunks = [471VSBuffer.fromString('abc'),472VSBuffer.fromString('def'),473VSBuffer.fromString('ghi')474];475476// Test without total length477const result1 = VSBuffer.concat(chunks);478assert.strictEqual(result1.toString(), 'abcdefghi');479480// Test with total length481const result2 = VSBuffer.concat(chunks, 9);482assert.strictEqual(result2.toString(), 'abcdefghi');483});484485test('clone', () => {486const original = VSBuffer.fromString('test');487const clone = original.clone();488489assert.notStrictEqual(original.buffer, clone.buffer);490assert.deepStrictEqual(Array.from(original.buffer), Array.from(clone.buffer));491});492493test('slice', () => {494const buff = VSBuffer.fromString('Hello World');495496const slice1 = buff.slice(0, 5);497assert.strictEqual(slice1.toString(), 'Hello');498499const slice2 = buff.slice(6);500assert.strictEqual(slice2.toString(), 'World');501});502503test('set', () => {504const buff = VSBuffer.alloc(5);505506// Test setting from VSBuffer507buff.set(VSBuffer.fromString('ab'), 0);508assert.strictEqual(buff.toString().substring(0, 2), 'ab');509510// Test setting from Uint8Array511buff.set(new Uint8Array([99, 100]), 2); // 'cd'512assert.strictEqual(buff.toString().substring(2, 4), 'cd');513514// Test invalid input515assert.throws(() => {516// eslint-disable-next-line local/code-no-any-casts517buff.set({} as any);518});519});520521test('equals', () => {522const buff1 = VSBuffer.fromString('test');523const buff2 = VSBuffer.fromString('test');524const buff3 = VSBuffer.fromString('different');525const buff4 = VSBuffer.fromString('tes1');526527assert.strictEqual(buff1.equals(buff1), true);528assert.strictEqual(buff1.equals(buff2), true);529assert.strictEqual(buff1.equals(buff3), false);530assert.strictEqual(buff1.equals(buff4), false);531});532533test('read/write methods', () => {534const buff = VSBuffer.alloc(8);535536// Test UInt32BE537buff.writeUInt32BE(0x12345678, 0);538assert.strictEqual(buff.readUInt32BE(0), 0x12345678);539540// Test UInt32LE541buff.writeUInt32LE(0x12345678, 4);542assert.strictEqual(buff.readUInt32LE(4), 0x12345678);543544// Test UInt8545const buff2 = VSBuffer.alloc(1);546buff2.writeUInt8(123, 0);547assert.strictEqual(buff2.readUInt8(0), 123);548});549550suite('encoding', () => {551/*552Generated with:553554const crypto = require('crypto');555556for (let i = 0; i < 16; i++) {557const buf = crypto.randomBytes(i);558console.log(`[new Uint8Array([${Array.from(buf).join(', ')}]), '${buf.toString('base64')}'],`)559}560561*/562563const testCases: [Uint8Array, base64: string, hex: string][] = [564[new Uint8Array([]), '', ''],565[new Uint8Array([77]), 'TQ==', '4d'],566[new Uint8Array([230, 138]), '5oo=', 'e68a'],567[new Uint8Array([104, 98, 82]), 'aGJS', '686252'],568[new Uint8Array([92, 114, 57, 209]), 'XHI50Q==', '5c7239d1'],569[new Uint8Array([238, 51, 1, 240, 124]), '7jMB8Hw=', 'ee3301f07c'],570[new Uint8Array([96, 54, 130, 79, 47, 179]), 'YDaCTy+z', '6036824f2fb3'],571[new Uint8Array([91, 22, 68, 217, 68, 117, 116]), 'WxZE2UR1dA==', '5b1644d9447574'],572[new Uint8Array([184, 227, 214, 171, 244, 175, 141, 53]), 'uOPWq/SvjTU=', 'b8e3d6abf4af8d35'],573[new Uint8Array([53, 98, 93, 130, 71, 117, 191, 137, 156]), 'NWJdgkd1v4mc', '35625d824775bf899c'],574[new Uint8Array([154, 156, 60, 102, 232, 197, 92, 25, 124, 98]), 'mpw8ZujFXBl8Yg==', '9a9c3c66e8c55c197c62'],575[new Uint8Array([152, 131, 106, 234, 17, 183, 164, 245, 252, 67, 26]), 'mINq6hG3pPX8Qxo=', '98836aea11b7a4f5fc431a'],576[new Uint8Array([232, 254, 194, 234, 16, 42, 86, 135, 117, 61, 179, 4]), '6P7C6hAqVod1PbME', 'e8fec2ea102a5687753db304'],577[new Uint8Array([4, 199, 85, 172, 125, 171, 172, 219, 61, 47, 78, 155, 127]), 'BMdVrH2rrNs9L06bfw==', '04c755ac7dabacdb3d2f4e9b7f'],578[new Uint8Array([189, 67, 62, 189, 87, 171, 27, 164, 87, 142, 126, 113, 23, 182]), 'vUM+vVerG6RXjn5xF7Y=', 'bd433ebd57ab1ba4578e7e7117b6'],579[new Uint8Array([153, 156, 145, 240, 228, 200, 199, 158, 40, 167, 97, 52, 217, 148, 43]), 'mZyR8OTIx54op2E02ZQr', '999c91f0e4c8c79e28a76134d9942b'],580];581582test('encodes base64', () => {583for (const [bytes, expected] of testCases) {584assert.strictEqual(encodeBase64(VSBuffer.wrap(bytes)), expected);585}586});587588test('decodes, base64', () => {589for (const [expected, encoded] of testCases) {590assert.deepStrictEqual(new Uint8Array(decodeBase64(encoded).buffer), expected);591}592});593594test('encodes hex', () => {595for (const [bytes, , expected] of testCases) {596assert.strictEqual(encodeHex(VSBuffer.wrap(bytes)), expected);597}598});599600test('decodes, hex', () => {601for (const [expected, , encoded] of testCases) {602assert.deepStrictEqual(new Uint8Array(decodeHex(encoded).buffer), expected);603}604});605606test('throws error on invalid encoding', () => {607assert.throws(() => decodeBase64('invalid!'));608assert.throws(() => decodeHex('invalid!'));609});610});611});612613614