From 4302941b06b51233b13cd1f7293a4f38e0ec8073 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 27 Jun 2020 21:56:39 +0200 Subject: [PATCH] fix(std/node): add fill & encoding args to Buffer.alloc (#6526) --- std/node/buffer.ts | 49 ++++++++++++++- std/node/buffer_test.ts | 135 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+), 2 deletions(-) diff --git a/std/node/buffer.ts b/std/node/buffer.ts index b9b33be993..e74ece196b 100644 --- a/std/node/buffer.ts +++ b/std/node/buffer.ts @@ -40,8 +40,53 @@ export default class Buffer extends Uint8Array { /** * Allocates a new Buffer of size bytes. */ - static alloc(size: number): Buffer { - return new Buffer(size); + static alloc( + size: number, + fill?: number | string | Uint8Array | Buffer, + encoding = "utf8" + ): Buffer { + if (typeof size !== "number") { + throw new TypeError( + `The "size" argument must be of type number. Received type ${typeof size}` + ); + } + + const buf = new Buffer(size); + if (size === 0) return buf; + + let bufFill; + if (typeof fill === "string") { + encoding = checkEncoding(encoding); + if (typeof fill === "string" && fill.length === 1 && encoding === "utf8") + buf.fill(fill.charCodeAt(0)); + else bufFill = Buffer.from(fill, encoding); + } else if (typeof fill === "number") buf.fill(fill); + else if (fill instanceof Uint8Array) { + if (fill.length === 0) { + throw new TypeError( + `The argument "value" is invalid. Received ${fill.constructor.name} []` + ); + } + + bufFill = fill; + } + + if (bufFill) { + if (bufFill.length > buf.length) + bufFill = bufFill.subarray(0, buf.length); + + let offset = 0; + while (offset < size) { + buf.set(bufFill, offset); + offset += bufFill.length; + if (offset + bufFill.length >= size) break; + } + if (offset !== size) { + buf.set(bufFill.subarray(0, size - offset), offset); + } + } + + return buf; } /** diff --git a/std/node/buffer_test.ts b/std/node/buffer_test.ts index adbc797515..2be7a70bbe 100644 --- a/std/node/buffer_test.ts +++ b/std/node/buffer_test.ts @@ -15,6 +15,58 @@ Deno.test({ }, }); +Deno.test({ + name: "alloc fails if size is not a number", + fn() { + const invalidSizes = [{}, "1", "foo", []]; + + for (const size of invalidSizes) { + assertThrows( + () => { + // deno-lint-ignore ban-ts-comment + // @ts-ignore + Buffer.alloc(size); + }, + TypeError, + `The "size" argument must be of type number. Received type ${typeof size}`, + "should throw on non-number size" + ); + } + }, +}); + +Deno.test({ + name: "alloc(>0) fails if value is an empty Buffer/Uint8Array", + fn() { + const invalidValues = [new Uint8Array(), Buffer.alloc(0)]; + + for (const value of invalidValues) { + assertThrows( + () => { + // deno-lint-ignore ban-ts-comment + // @ts-ignore + console.log(value.constructor.name); + Buffer.alloc(1, value); + }, + TypeError, + `The argument "value" is invalid. Received ${value.constructor.name} []`, + "should throw for empty Buffer/Uint8Array" + ); + } + }, +}); + +Deno.test({ + name: "alloc(0) doesn't fail if value is an empty Buffer/Uint8Array", + fn() { + const invalidValues = [new Uint8Array(), Buffer.alloc(0)]; + + for (const value of invalidValues) { + assertEquals(Buffer.alloc(0, value).length, 0); + } + }, +}); + Deno.test({ name: "alloc allocates a buffer with the expected size", fn() { @@ -32,6 +84,89 @@ Deno.test({ }, }); +Deno.test({ + name: "alloc filled correctly with integer", + fn() { + const buffer: Buffer = Buffer.alloc(3, 5); + assertEquals(buffer, new Uint8Array([5, 5, 5])); + }, +}); + +Deno.test({ + name: "alloc filled correctly with single character", + fn() { + assertEquals(Buffer.alloc(5, "a"), new Uint8Array([97, 97, 97, 97, 97])); + }, +}); + +Deno.test({ + name: "alloc filled correctly with base64 string", + fn() { + assertEquals( + Buffer.alloc(11, "aGVsbG8gd29ybGQ=", "base64"), + new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]) + ); + }, +}); + +Deno.test({ + name: "alloc filled correctly with hex string", + fn() { + assertEquals( + Buffer.alloc(4, "64656e6f", "hex"), + new Uint8Array([100, 101, 110, 111]) + ); + }, +}); + +Deno.test({ + name: "alloc filled correctly with hex string smaller than alloc size", + fn() { + assertEquals( + Buffer.alloc(13, "64656e6f", "hex").toString(), + "denodenodenod" + ); + }, +}); + +Deno.test({ + name: "alloc filled correctly with Uint8Array smaller than alloc size", + fn() { + assertEquals( + Buffer.alloc(7, new Uint8Array([100, 101])), + new Uint8Array([100, 101, 100, 101, 100, 101, 100]) + ); + assertEquals( + Buffer.alloc(6, new Uint8Array([100, 101])), + new Uint8Array([100, 101, 100, 101, 100, 101]) + ); + }, +}); + +Deno.test({ + name: "alloc filled correctly with Uint8Array bigger than alloc size", + fn() { + assertEquals( + Buffer.alloc(1, new Uint8Array([100, 101])), + new Uint8Array([100]) + ); + }, +}); + +Deno.test({ + name: "alloc filled correctly with Buffer", + fn() { + assertEquals( + Buffer.alloc(6, new Buffer([100, 101])), + new Uint8Array([100, 101, 100, 101, 100, 101]) + ); + assertEquals( + Buffer.alloc(7, new Buffer([100, 101])), + new Uint8Array([100, 101, 100, 101, 100, 101, 100]) + ); + }, +}); + Deno.test({ name: "Byte length is the expected for strings", fn() {