/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
tests/unit_node/buffer_test.ts
1 338 строк
38 KB
Tomas Zijdemans
perf(ext/web): apply the base64url op design to standard base64 (#36422)
10 авг 2026, 17:26
Не верифицирован
10 авг 2026, 17:26
ca568b1
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. import { Buffer, constants, File as BufferFile, resolveObjectURL, transcode, } from "node:buffer"; import { assertEquals, assertThrows } from "@std/assert"; import { strictEqual } from "node:assert"; const { MAX_STRING_LENGTH } = constants; Deno.test({ name: "[node/buffer] 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-expect-error Buffer.alloc(size); }, TypeError, '"size" argument must be of type number', "should throw on non-number size", ); } }, }); Deno.test({ name: "[node/buffer] alloc allocates a buffer with the expected size", fn() { const buffer: Buffer = Buffer.alloc(1); assertEquals(buffer.length, 1, "Buffer size should be 1"); assertEquals(buffer[0], 0, "Content should be filled with 0"); }, }); Deno.test({ name: "[node/buffer] alloc(0) creates an empty buffer", fn() { const buffer: Buffer = Buffer.alloc(0); assertEquals(buffer.length, 0, "Buffer size should be 0"); }, }); Deno.test({ name: "[node/buffer] allocUnsafe allocates a buffer with the expected size", fn() { const buffer: Buffer = Buffer.allocUnsafe(1); assertEquals(buffer.length, 1, "Buffer size should be 1"); }, }); Deno.test({ name: "[node/buffer] allocUnsafe(0) creates an empty buffer", fn() { const buffer: Buffer = Buffer.allocUnsafe(0); assertEquals(buffer.length, 0, "Buffer size should be 0"); }, }); Deno.test({ name: "[node/buffer] alloc filled correctly with integer", fn() { const buffer: Buffer = Buffer.alloc(3, 5); assertEquals(buffer, Buffer.from([5, 5, 5])); }, }); Deno.test({ name: "[node/buffer] alloc filled correctly with single character", fn() { assertEquals(Buffer.alloc(5, "a"), Buffer.from([97, 97, 97, 97, 97])); }, }); Deno.test({ name: "[node/buffer] alloc filled correctly with base64 string", fn() { assertEquals( Buffer.alloc(11, "aGVsbG8gd29ybGQ=", "base64"), Buffer.from([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), ); }, }); Deno.test({ name: "[node/buffer] alloc filled correctly with hex string", fn() { assertEquals( Buffer.alloc(4, "64656e6f", "hex"), Buffer.from([100, 101, 110, 111]), ); }, }); Deno.test({ name: "[node/buffer] alloc filled correctly with hex string smaller than alloc size", fn() { assertEquals( Buffer.alloc(13, "64656e6f", "hex").toString(), "denodenodenod", ); }, }); Deno.test({ name: "[node/buffer] alloc filled correctly with Uint8Array smaller than alloc size", fn() { // todo(fbaltor): remove this 'any' when @types/node fixes https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/65831 // deno-lint-ignore no-explicit-any const arr: any = new Uint8Array([100, 101]); assertEquals( Buffer.alloc(7, arr), Buffer.from([100, 101, 100, 101, 100, 101, 100]), ); assertEquals( Buffer.alloc(6, arr), Buffer.from([100, 101, 100, 101, 100, 101]), ); }, }); Deno.test({ name: "[node/buffer] alloc filled correctly with Uint8Array bigger than alloc size", fn() { assertEquals( // todo(fbaltor): remove this 'any' when @types/node fixes https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/65831 // deno-lint-ignore no-explicit-any Buffer.alloc(1, new Uint8Array([100, 101]) as any), Buffer.from([100]), ); }, }); Deno.test({ name: "[node/buffer] alloc filled correctly with Buffer", fn() { assertEquals( Buffer.alloc(6, Buffer.from([100, 101])), Buffer.from([100, 101, 100, 101, 100, 101]), ); assertEquals( Buffer.alloc(7, Buffer.from([100, 101])), Buffer.from([100, 101, 100, 101, 100, 101, 100]), ); }, }); // tests from: // https://github.com/nodejs/node/blob/56dbe466fdbc598baea3bfce289bf52b97b8b8f7/test/parallel/test-buffer-bytelength.js#L70 Deno.test({ name: "[node/buffer] Byte length is the expected for strings", fn() { // Special case: zero length string assertEquals(Buffer.byteLength("", "ascii"), 0); // deno-lint-ignore no-explicit-any assertEquals(Buffer.byteLength("", "HeX" as any), 0); // utf8 assertEquals(Buffer.byteLength("∑éllö wørl∂!", "utf-8"), 19); assertEquals(Buffer.byteLength("κλμνξο", "utf8"), 12); assertEquals(Buffer.byteLength("挵挶挷挸挹", "utf-8"), 15); // deno-lint-ignore no-explicit-any assertEquals(Buffer.byteLength("𠝹𠱓𠱸", "UTF8" as any), 12); // Without an encoding, utf8 should be assumed assertEquals(Buffer.byteLength("hey there"), 9); assertEquals(Buffer.byteLength("𠱸挶νξ#xx :)"), 17); // deno-lint-ignore no-explicit-any assertEquals(Buffer.byteLength("hello world", "" as any), 11); // It should also be assumed with unrecognized encoding // deno-lint-ignore no-explicit-any assertEquals(Buffer.byteLength("hello world", "abc" as any), 11); // deno-lint-ignore no-explicit-any assertEquals(Buffer.byteLength("ßœ∑≈", "unkn0wn enc0ding" as any), 10); // base64 assertEquals(Buffer.byteLength("aGVsbG8gd29ybGQ=", "base64"), 11); // deno-lint-ignore no-explicit-any assertEquals(Buffer.byteLength("aGVsbG8gd29ybGQ=", "BASE64" as any), 11); assertEquals(Buffer.byteLength("bm9kZS5qcyByb2NrcyE=", "base64"), 14); assertEquals(Buffer.byteLength("aGkk", "base64"), 3); assertEquals( Buffer.byteLength("bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw==", "base64"), 25, ); // special padding assertEquals(Buffer.byteLength("aaa=", "base64"), 2); assertEquals(Buffer.byteLength("aaaa==", "base64"), 3); assertEquals(Buffer.byteLength("Il était tué"), 14); assertEquals(Buffer.byteLength("Il était tué", "utf8"), 14); ["ascii", "latin1", "binary"] .reduce((es: string[], e: string) => es.concat(e, e.toUpperCase()), []) .forEach((encoding: string) => { // deno-lint-ignore no-explicit-any assertEquals(Buffer.byteLength("Il était tué", encoding as any), 12); }); ["ucs2", "ucs-2", "utf16le", "utf-16le"] .reduce((es: string[], e: string) => es.concat(e, e.toUpperCase()), []) .forEach((encoding: string) => { // deno-lint-ignore no-explicit-any assertEquals(Buffer.byteLength("Il était tué", encoding as any), 24); }); }, }); Deno.test({ name: "[node/buffer] Byte length is the expected one for non-strings", fn() { assertEquals( Buffer.byteLength(Buffer.alloc(0)), Buffer.alloc(0).byteLength, "Byte length differs on buffers", ); }, }); Deno.test({ name: "[node/buffer] Two Buffers are concatenated", fn() { const data1 = [1, 2, 3]; const data2 = [4, 5, 6]; const buffer1 = Buffer.from(data1); const buffer2 = Buffer.from(data2); const resultBuffer = Buffer.concat([buffer1, buffer2]); const expectedBuffer = Buffer.from([...data1, ...data2]); assertEquals(resultBuffer, expectedBuffer); }, }); Deno.test({ name: "[node/buffer] A single buffer concatenates and return the same buffer", fn() { const buffer1 = Buffer.alloc(1); const resultBuffer = Buffer.concat([buffer1]); assertEquals(resultBuffer.length, 1, "Buffer length should be 1"); }, }); Deno.test({ name: "[node/buffer] No buffers concat returns an empty buffer", fn() { const resultBuffer = Buffer.concat([]); assertEquals(resultBuffer.length, 0, "Buffer length should be 0"); }, }); Deno.test({ name: "[node/buffer] Buffer concat respects totalLength parameter", fn() { const maxLength1 = 10; const buffer1 = Buffer.alloc(2); const buffer2 = Buffer.alloc(2); assertEquals( Buffer.concat([buffer1, buffer2], maxLength1).length, maxLength1, ); const maxLength2 = 3; const buffer3 = Buffer.alloc(2); const buffer4 = Buffer.alloc(2); assertEquals( Buffer.concat([buffer3, buffer4], maxLength2).length, maxLength2, ); }, }); Deno.test({ name: "[node/buffer] Buffer.allocUnsafe does not truncate lengths > 2^32", ignore: true, // requires >4GB of memory fn() { const size = 2 ** 32 + 5; const buf = Buffer.allocUnsafe(size); assertEquals(buf.length, size); }, }); Deno.test({ name: "[node/buffer] Buffer concat does not truncate buffers larger than 4GB", ignore: true, // requires >4GB of memory fn() { const size = 2 ** 32 + 5; const largeBuffer = Buffer.alloc(size); largeBuffer.fill(111); const result = Buffer.concat([largeBuffer]); assertEquals(result.length, size); assertEquals(Array.from(result.subarray(0, 5)), [111, 111, 111, 111, 111]); }, }); Deno.test({ name: "[node/buffer] Buffer 8 bit unsigned integers", fn() { const buffer = Buffer.from([0xff, 0x2a, 0x2a, 0x2a]); assertEquals(buffer.readUInt8(0), 255); assertEquals(buffer.readUInt8(1), 42); assertEquals(buffer.readUInt8(2), 42); assertEquals(buffer.readUInt8(3), 42); }, }); Deno.test({ name: "[node/buffer] Buffer 16 bit unsigned integers", fn() { const buffer = Buffer.from([0x00, 0x2a, 0x42, 0x3f]); assertEquals(buffer.readUInt16BE(0), 0x2a); assertEquals(buffer.readUInt16BE(1), 0x2a42); assertEquals(buffer.readUInt16BE(2), 0x423f); assertEquals(buffer.readUInt16LE(0), 0x2a00); assertEquals(buffer.readUInt16LE(1), 0x422a); assertEquals(buffer.readUInt16LE(2), 0x3f42); buffer[0] = 0xfe; buffer[1] = 0xfe; assertEquals(buffer.readUInt16BE(0), 0xfefe); assertEquals(buffer.readUInt16LE(0), 0xfefe); }, }); Deno.test({ name: "[node/buffer] Buffer 32 bit unsigned integers", fn() { const buffer = Buffer.from([0x32, 0x65, 0x42, 0x56, 0x23, 0xff]); assertEquals(buffer.readUInt32BE(0), 0x32654256); assertEquals(buffer.readUInt32BE(1), 0x65425623); assertEquals(buffer.readUInt32BE(2), 0x425623ff); assertEquals(buffer.readUInt32LE(0), 0x56426532); assertEquals(buffer.readUInt32LE(1), 0x23564265); assertEquals(buffer.readUInt32LE(2), 0xff235642); }, }); Deno.test({ name: "[node/buffer] Buffer readUIntBE", fn() { const buffer = Buffer.from([ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ]); assertEquals(buffer.readUIntBE(0, 1), 0x01); assertEquals(buffer.readUIntBE(0, 2), 0x0102); assertEquals(buffer.readUIntBE(0, 4), 0x01020304); }, }); Deno.test({ name: "[node/buffer] Buffer readUIntLE", fn() { const buffer = Buffer.from([ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ]); assertEquals(buffer.readUIntLE(0, 1), 0x01); assertEquals(buffer.readUIntLE(0, 2), 0x0201); assertEquals(buffer.readUIntLE(0, 4), 0x04030201); }, }); Deno.test({ name: "[node/buffer] Buffer copy works as expected", fn() { const data1 = new Uint8Array([1, 2, 3]); const data2 = new Uint8Array([4, 5, 6]); const buffer1 = Buffer.from(data1); const buffer2 = Buffer.from(data2); //Mutates data_1 data1.set(data2); //Mutates buffer_1 buffer2.copy(buffer1); assertEquals( Buffer.from(data1), buffer1, ); }, }); Deno.test({ name: "[node/buffer] Buffer copy respects the starting point for copy", fn() { const buffer1 = Buffer.from([1, 2, 3]); const buffer2 = Buffer.alloc(8); buffer1.copy(buffer2, 5); const expected = Buffer.from([0, 0, 0, 0, 0, 1, 2, 3]); assertEquals( buffer2, expected, ); }, }); Deno.test({ name: "[node/buffer] Buffer copy doesn't throw on offset but copies until offset reached", fn() { const buffer1 = Buffer.from([1, 2, 3]); const buffer2 = Buffer.alloc(8); const writtenBytes1 = buffer1.copy(buffer2, 6); assertEquals( writtenBytes1, 2, ); assertEquals( buffer2, Buffer.from([0, 0, 0, 0, 0, 0, 1, 2]), ); const buffer3 = Buffer.from([1, 2, 3]); const buffer4 = Buffer.alloc(8); const writtenBytes2 = buffer3.copy(buffer4, 8); assertEquals( writtenBytes2, 0, ); assertEquals( buffer4, Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), ); }, }); Deno.test({ name: "[node/buffer] Buffer from string creates a Buffer", fn() { const buffer: Buffer = Buffer.from("test"); assertEquals(buffer.length, 4, "Buffer length should be 4"); assertEquals( buffer.toString(), "test", "Buffer to string should recover the string", ); }, }); Deno.test({ name: "[node/buffer] Buffer from string hex", fn() { for (const encoding of ["hex", "HEX"]) { const buffer: Buffer = Buffer.from( "7468697320697320612074c3a97374", // deno-lint-ignore no-explicit-any encoding as any, ); assertEquals(buffer.length, 15, "Buffer length should be 15"); assertEquals( buffer.toString(), "this is a tést", "Buffer to string should recover the string", ); } }, }); Deno.test({ name: "[node/buffer] Buffer from string base64", fn() { for (const encoding of ["base64", "BASE64"]) { const buffer: Buffer = Buffer.from( "dGhpcyBpcyBhIHTDqXN0", // deno-lint-ignore no-explicit-any encoding as any, ); assertEquals(buffer.length, 15, "Buffer length should be 15"); assertEquals( buffer.toString(), "this is a tést", "Buffer to string should recover the string", ); } }, }); // https://github.com/denoland/deno/issues/24908 Deno.test({ name: "[node/buffer] Buffer from base64 with non-base64 characters", fn() { // Strings with hyphens should not throw const buf1 = Buffer.from("base64-encoded-bytes-from-browser", "base64"); assertEquals(buf1.length, 24); assertEquals( buf1.toString("hex"), "6dab1eeb8f9e9dca1d79df9bcad7acf9fae89be6eba30b1e", ); const buf2 = Buffer.from("not-valid-base64!!!", "base64"); assertEquals(buf2.length, 12); // Single character (too short for base64) assertEquals(Buffer.from("A", "base64").length, 0); }, }); Deno.test({ name: "[node/buffer] Buffer.from base64 accepts dirty input", fn() { const expected = Buffer.from("hello world"); // Unpadded, padded, and whitespace-laced input decodes without cleaning. assertEquals(Buffer.from("aGVsbG8gd29ybGQ", "base64"), expected); assertEquals(Buffer.from("aGVsbG8gd29ybGQ=", "base64"), expected); assertEquals(Buffer.from("aGVs bG8g\nd29y\tbGQ", "base64"), expected); // base64url alphabet maps onto the standard one (Node cleaning // semantics). assertEquals( Buffer.from("-_-_", "base64"), Buffer.from([0xfb, 0xff, 0xbf]), ); // Junk characters are stripped; everything after '=' is dropped. assertEquals(Buffer.from("aGVsbG8!gd29ybGQ", "base64"), expected); assertEquals( Buffer.from("aGVsbG8=gd29ybGQ", "base64").toString(), "hello", ); // Characters above U+00FF take the cleaning path via the catch. assertEquals(Buffer.from("aGVsbG8\u{1F600}gd29ybGQ", "base64"), expected); assertEquals(Buffer.from("!!!", "base64").length, 0); }, }); Deno.test({ name: "[node/buffer] base64 write truncates into small targets", fn() { const small = Buffer.alloc(2); assertEquals(small.write("aGVsbG8gd29ybGQ=", "base64"), 2); assertEquals(small.toString(), "he"); const buf = Buffer.alloc(16, 0x2e); assertEquals(buf.write("aGVsbG8=", 3, "base64"), 5); assertEquals(buf.toString("latin1"), "...hello........"); // Dirty input truncates through the cleaning fallback too. const dirty = Buffer.alloc(2); assertEquals(dirty.write("aGVs bG8!gd29ybGQ", "base64"), 2); assertEquals(dirty.toString(), "he"); }, }); Deno.test({ name: "[node/buffer] Buffer to string base64", fn() { for (const encoding of ["base64", "BASE64"]) { const buffer: Buffer = Buffer.from("deno land"); assertEquals( // deno-lint-ignore no-explicit-any buffer.toString(encoding as any), "ZGVubyBsYW5k", "Buffer to string should recover the string in base64", ); } const b64 = "dGhpcyBpcyBhIHTDqXN0"; assertEquals(Buffer.from(b64, "base64").toString("base64"), b64); }, }); Deno.test({ name: "[node/buffer] Buffer to string hex", fn() { for (const encoding of ["hex", "HEX"]) { const buffer: Buffer = Buffer.from("deno land"); assertEquals( // deno-lint-ignore no-explicit-any buffer.toString(encoding as any), "64656e6f206c616e64", "Buffer to string should recover the string", ); } const hex = "64656e6f206c616e64"; assertEquals(Buffer.from(hex, "hex").toString("hex"), hex); }, }); Deno.test({ name: "[node/buffer] Buffer from string invalid encoding", fn() { const defaultToUtf8Encodings = [null, 5, {}, true, false, ""]; const invalidEncodings = ["deno", "base645"]; for (const encoding of defaultToUtf8Encodings) { // deno-lint-ignore no-explicit-any assertEquals(Buffer.from("yes", encoding as any).toString(), "yes"); } for (const encoding of invalidEncodings) { assertThrows( () => { // deno-lint-ignore no-explicit-any Buffer.from("yes", encoding as any); }, TypeError, `Unknown encoding: ${encoding}`, ); } }, }); Deno.test({ name: "[node/buffer] Buffer from another buffer creates a copy", fn() { const buffer1: Buffer = Buffer.from("test"); const buffer2: Buffer = Buffer.from(buffer1); assertEquals(buffer2.length, 4, "Buffer length should be 4"); assertEquals( buffer2.toString(), "test", "Buffer to string should recover the string", ); buffer1[0] = 114; assertEquals(buffer2.toString(), "test", "Buffer should be a copy"); }, }); Deno.test({ name: "[node/buffer] isBuffer returns true if the object is a buffer", fn() { assertEquals(Buffer.isBuffer(Buffer.from("test")), true); }, }); Deno.test({ name: "[node/buffer] isBuffer returns false if the object is not a buffer", fn() { assertEquals(Buffer.isBuffer({ test: 3 }), false); assertEquals(Buffer.isBuffer(new Uint8Array()), false); }, }); Deno.test({ name: "[node/buffer] Buffer toJSON", fn() { assertEquals( JSON.stringify(Buffer.from("deno")), '{"type":"Buffer","data":[100,101,110,111]}', ); }, }); Deno.test({ name: "[node/buffer] slice does not create a copy", fn() { const buf = Buffer.from("ceno"); // This method is not compatible with the Uint8Array.prototype.slice() const slice = buf.slice(); slice[0]++; assertEquals(slice.toString(), "deno"); }, }); Deno.test({ name: "[node/buffer] slice with infinity returns empty buffer", fn() { const buf = Buffer.from([1, 2, 3, 4, 5]); assertEquals(buf.slice(Infinity).length, 0); }, }); // https://github.com/denoland/deno/issues/34286 Deno.test({ name: "[node/buffer] base64Slice allows omitting arguments", fn() { const buf = Buffer.of(1, 2, 3); // @ts-expect-error Buffer.prototype.base64Slice is an undocumented API assertEquals(buf.base64Slice(), "AQID"); // @ts-expect-error Buffer.prototype.base64Slice is an undocumented API assertEquals(buf.base64Slice(0, 3), "AQID"); }, }); Deno.test({ name: "[node/buffer] base64Slice validates its range", fn() { const buf = Buffer.alloc(10); assertThrows( () => { // @ts-expect-error Buffer.prototype.base64Slice is undocumented buf.base64Slice(20, 25); }, RangeError, ); assertThrows( () => { // @ts-expect-error Buffer.prototype.base64Slice is undocumented buf.base64Slice(0, 20); }, RangeError, ); // @ts-expect-error Buffer.prototype.base64Slice is undocumented assertEquals(buf.base64Slice(5, 4), ""); }, }); Deno.test({ name: "[node/buffer] base64Write validates its offset", fn() { const buf = Buffer.alloc(10); assertThrows( () => { Buffer.prototype.base64Write.call(buf, "YmFzZTY0", 100); }, RangeError, ); }, }); Deno.test({ name: "[node/buffer] base64 write respects the length limit", fn() { const buf = Buffer.alloc(64); buf.fill(0x61, 32); const input = Buffer.from("B".repeat(48)).toString("base64"); assertEquals(buf.write(input, 0, 32, "base64"), 32); assertEquals(buf.subarray(0, 32), Buffer.alloc(32, 0x42)); assertEquals(buf.subarray(32), Buffer.alloc(32, 0x61)); }, }); Deno.test({ name: "[node/buffer] base64 operations use the actual buffer length", fn() { const buf = Buffer.from("abcdef"); Object.defineProperty(buf, "byteLength", { value: 0 }); assertEquals(buf.toString("base64", 1, 4), "YmNk"); assertEquals(buf.write("WFla", 1, 2, "base64"), 2); assertEquals(buf.toString(), "aXYdef"); }, }); Deno.test({ name: "[node/buffer] base64urlSlice allows omitting arguments", fn() { const buf = Buffer.of(1, 2, 3); // @ts-expect-error Buffer.prototype.base64urlSlice is an undocumented API assertEquals(buf.base64urlSlice(), "AQID"); // @ts-expect-error Buffer.prototype.base64urlSlice is an undocumented API assertEquals(buf.base64urlSlice(0, 3), "AQID"); }, }); Deno.test({ name: "[node/buffer] base64url round-trips", fn() { for ( const bytes of [ [], [0], [0xfb], [0xfb, 0xff], [0xfb, 0xff, 0x7e], [0xfb, 0xff, 0x7e, 0x00], ] ) { const buf = Buffer.from(bytes); const encoded = buf.toString("base64url"); // URL-safe alphabet, no padding. assertEquals(/^[-_A-Za-z0-9]*$/.test(encoded), true); assertEquals(Buffer.from(encoded, "base64url"), buf); } // Larger than the op's 8 KiB stack buffer. const bytes = new Uint8Array(65536); for (let i = 0; i < bytes.length; i++) bytes[i] = (i * 31) & 0xff; const big = Buffer.from(bytes); assertEquals(Buffer.from(big.toString("base64url"), "base64url"), big); }, }); Deno.test({ name: "[node/buffer] base64url sub-range toString", fn() { const buf = Buffer.from("hello world"); assertEquals(buf.toString("base64url", 1, 5), "ZWxsbw"); assertEquals(buf.toString("base64url", 0, buf.length), "aGVsbG8gd29ybGQ"); assertEquals(buf.toString("base64url", 4, 4), ""); // Out-of-range bounds are clamped by toString. assertEquals(buf.toString("base64url", -5, 100), "aGVsbG8gd29ybGQ"); }, }); Deno.test({ name: "[node/buffer] Buffer.from base64url accepts dirty input", fn() { const expected = Buffer.from("hello world"); // Padded and unpadded. assertEquals(Buffer.from("aGVsbG8gd29ybGQ", "base64url"), expected); assertEquals(Buffer.from("aGVsbG8gd29ybGQ=", "base64url"), expected); // Whitespace-laced. assertEquals(Buffer.from("aGVs bG8g\nd29y\tbGQ", "base64url"), expected); // Mixed/standard alphabet (Node cleaning semantics). assertEquals( Buffer.from("+/+/", "base64url"), Buffer.from([0xfb, 0xff, 0xbf]), ); // Junk characters are stripped; everything after '=' is dropped. assertEquals(Buffer.from("aGVsbG8!gd29ybGQ", "base64url"), expected); assertEquals( Buffer.from("aGVsbG8=gd29ybGQ", "base64url").toString(), "hello", ); assertEquals(Buffer.from("!!!", "base64url").length, 0); }, }); Deno.test({ name: "[node/buffer] base64url write truncates into small targets", fn() { const small = Buffer.alloc(2); assertEquals(small.write("aGVsbG8gd29ybGQ", "base64url"), 2); assertEquals(small.toString(), "he"); const buf = Buffer.alloc(16, 0x2e); assertEquals(buf.write("aGVsbG8", 3, "base64url"), 5); assertEquals(buf.toString("latin1"), "...hello........"); const limited = Buffer.alloc(64); limited.fill(0x61, 32); const input = Buffer.from("B".repeat(48)).toString("base64url"); assertEquals(limited.write(input, 0, 32, "base64url"), 32); assertEquals(limited.subarray(0, 32), Buffer.alloc(32, 0x42)); assertEquals(limited.subarray(32), Buffer.alloc(32, 0x61)); }, }); Deno.test({ name: "[node/buffer] base64urlWrite validates its offset", fn() { const buf = Buffer.alloc(10); assertThrows( () => { Buffer.prototype.base64urlWrite.call(buf, "YmFzZTY0", 100); }, RangeError, ); }, }); Deno.test({ name: "[node/buffer] base64url on views with non-zero byteOffset", fn() { const ab = new ArrayBuffer(32); const raw = new Uint8Array(ab); for (let i = 0; i < raw.length; i++) raw[i] = i; // The ops receive the view, not the whole ArrayBuffer. const view = Buffer.from(ab, 8, 16); const copy = Buffer.from(raw.slice(8, 24)); assertEquals(view.toString("base64url"), copy.toString("base64url")); assertEquals( view.toString("base64url", 1, 5), copy.toString("base64url", 1, 5), ); // Writes land inside the view and leave the rest of the buffer alone. assertEquals(view.write("_____w", 2, "base64url"), 4); assertEquals(Array.from(raw.subarray(10, 14)), [0xff, 0xff, 0xff, 0xff]); assertEquals(raw[9], 9); assertEquals(raw[14], 14); assertEquals(raw[24], 24); }, }); Deno.test({ name: "[node/buffer] base64 on views with non-zero byteOffset", fn() { const ab = new ArrayBuffer(32); const raw = new Uint8Array(ab); for (let i = 0; i < raw.length; i++) raw[i] = i; // The ops receive the view, not the whole ArrayBuffer. const view = Buffer.from(ab, 8, 16); const copy = Buffer.from(raw.slice(8, 24)); assertEquals(view.toString("base64"), copy.toString("base64")); assertEquals( view.toString("base64", 1, 5), copy.toString("base64", 1, 5), ); // Unpadded input takes the loose path; padded input the strict path. // Both land inside the view and leave the rest of the buffer alone. assertEquals(view.write("//////", 2, "base64"), 4); assertEquals(Array.from(raw.subarray(10, 14)), [0xff, 0xff, 0xff, 0xff]); assertEquals(view.write("AQIDBA==", 10, "base64"), 4); assertEquals(Array.from(raw.subarray(18, 22)), [1, 2, 3, 4]); assertEquals(raw[9], 9); assertEquals(raw[14], 14); assertEquals(raw[17], 17); assertEquals(raw[24], 24); }, }); Deno.test({ name: "[node/buffer] isEncoding returns true for valid encodings", fn() { [ "hex", "HEX", "HeX", "utf8", "utf-8", "ascii", "latin1", "binary", "base64", "BASE64", "BASe64", "ucs2", "ucs-2", "utf16le", "utf-16le", ].forEach((enc) => { assertEquals(Buffer.isEncoding(enc), true); }); }, }); Deno.test({ name: "[node/buffer] isEncoding returns false for invalid encodings", fn() { [ "utf9", "utf-7", "Unicode-FTW", "new gnu gun", false, NaN, {}, Infinity, [], 1, 0, -1, ].forEach((enc) => { // @ts-expect-error This deliberately ignores the type constraint assertEquals(Buffer.isEncoding(enc), false); }); }, }); Deno.test({ name: "[node/buffer] utf8Write handle missing optional length argument (https://github.com/denoland/deno_std/issues/2046)", fn() { const buf = Buffer.alloc(8); // @ts-expect-error Buffer.prototype.utf8Write is an undocumented API assertEquals(buf.utf8Write("abc", 0), 3); assertEquals([...buf], [0x61, 0x62, 0x63, 0, 0, 0, 0, 0]); }, }); Deno.test({ name: "[node/buffer] Buffer.from pool", fn() { const a = Buffer.from("hello world"); const b = Buffer.from("hello world"); strictEqual(a.buffer, b.buffer); }, }); Deno.test({ name: "[node/buffer] toString('utf8') keeps BOM", fn() { assertEquals( Buffer.from([239, 187, 191, 97, 98]).toString("utf8"), "\uFEFFab", ); }, }); Deno.test({ name: "[node/buffer] throws ERR_STRING_TOO_LONG with the correct message", fn() { assertThrows( () => { Buffer.allocUnsafe(2 ** 31).toString(); }, Error, `Cannot create a string longer than 0x${ MAX_STRING_LENGTH.toString(16) } characters`, ); }, }); Deno.test({ name: "[node/buffer] Buffer.from with hex encoding should truncate first non-hex character", fn() { const buf = Buffer.from("00aafffz", "hex"); assertEquals(buf, Buffer.from([0x00, 0xaa, 0xff])); const buf2 = Buffer.from("zz34", "hex"); assertEquals(buf2, Buffer.from([])); const buf3 = Buffer.from("123😁aa", "hex"); assertEquals(buf3, Buffer.from([0x12])); }, }); Deno.test({ name: "[node/buffer] File is exported from node:buffer", fn() { assertEquals(typeof BufferFile, "function"); const file = new BufferFile(["hello"], "hello.txt", { type: "text/plain", }); assertEquals(file.name, "hello.txt"); assertEquals(file.type, "text/plain"); assertEquals(file.size, 5); assertEquals(file instanceof Blob, true); }, }); Deno.test({ name: "[node/buffer] latin1Slice returns correct string", fn() { // deno-lint-ignore no-explicit-any const buf: any = Buffer.of(1, 2, 3, 0xff); assertEquals(buf.latin1Slice().length, 4); assertEquals(buf.latin1Slice(), "\x01\x02\x03\xff"); assertEquals(buf.latin1Slice(1, 3), "\x02\x03"); assertEquals(buf.latin1Slice(1, 0), ""); }, }); Deno.test({ name: "[node/buffer] asciiSlice returns correct string", fn() { // deno-lint-ignore no-explicit-any const buf: any = Buffer.of(1, 2, 3, 0x80, 0x81, 0x82, 0x83, 0xc0, 0xff); assertEquals(buf.asciiSlice().length, 9); assertEquals(buf.asciiSlice(), "\x01\x02\x03\x00\x01\x02\x03\x40\x7f"); assertEquals(buf.asciiSlice(1, 3), "\x02\x03"); // test `new_external_onebyte` // ZERO_COPY_THRESHOLD 1024 // // deno-lint-ignore no-explicit-any const buf1111: any = Buffer.alloc(1111); for (let i = 0, len = buf1111.length; i < len; i++) { buf1111[i] = Math.random() * 128; } const target1111: string = buf1111.latin1Slice(); assertEquals(buf1111.asciiSlice(), target1111); }, }); Deno.test({ name: "[node/buffer] ucs2Slice returns correct string", fn() { // deno-lint-ignore no-explicit-any const buf: any = Buffer.of( 0x60, 0x4f, 0x7d, 0x59, 0x44, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x6f, 0x00, ); assertEquals(buf.ucs2Slice().length, 6); assertEquals(buf.ucs2Slice(), "你好Deno"); assertEquals(buf.ucs2Slice(0, 4), "你好"); assertEquals(buf.ucs2Slice(4, 12), "Deno"); assertEquals(buf.ucs2Slice(0, 3), "你"); assertEquals(buf.ucs2Slice(1, 4), "絏"); assertEquals(buf.ucs2Slice(1, 6), "絏䑙"); // deno-lint-ignore no-explicit-any const oddBuf: any = Buffer.of(0x60, 0x4f, 0x7d, 0x59, 0x44); assertEquals(oddBuf.ucs2Slice(), "你好"); // test `new_external_twobyte` // ZERO_COPY_THRESHOLD 1024 // // deno-lint-ignore no-explicit-any const buf2001: any = Buffer.alloc(2001); for (let i = 1, len = buf2001.length; i < len; i++) { buf2001[i] = Math.random() * 128; } const target2000: string = buf2001.ucs2Slice(1, 1001) + buf2001.ucs2Slice(1001); assertEquals(buf2001.ucs2Slice(1), target2000); }, }); Deno.test({ name: "[node/buffer] utf8Slice handles buffer detach during index coercion", fn() { // deno-lint-ignore no-explicit-any const buf: any = Buffer.alloc(1024); const arrayBuffer = buf.buffer; const start = { valueOf() { structuredClone(arrayBuffer, { transfer: [arrayBuffer] }); return 0; }, }; assertThrows( () => buf.utf8Slice(start, 10), RangeError, "Index out of range", ); assertEquals(arrayBuffer.byteLength, 0); }, }); Deno.test({ name: "[node/buffer] hexSlice returns correct string", fn() { // deno-lint-ignore no-explicit-any const buf: any = Buffer.of(1, 2, 3, 0xff); assertEquals(buf.hexSlice(), "010203ff"); assertEquals(buf.hexSlice(1, 3), "0203"); // deno-lint-ignore no-explicit-any const emptyBuf: any = Buffer.of(); assertEquals(emptyBuf.hexSlice(), ""); // test `new_external_onebyte` // ZERO_COPY_THRESHOLD 1024 // // deno-lint-ignore no-explicit-any const buf1111: any = Buffer.alloc(1111); for (let i = 0, len = buf1111.length; i < len; i++) { buf1111[i] = Math.random() * 128; } const target1111: string = buf1111.toHex(); assertEquals(buf1111.hexSlice(), target1111); }, }); Deno.test({ name: "[node/buffer] resolveObjectURL resolves blob URL", async fn() { const blob = new Blob(["hello"]); const url = URL.createObjectURL(blob); try { const resolved = resolveObjectURL(url); assertEquals(resolved instanceof Blob, true); assertEquals(resolved!.size, 5); assertEquals( Buffer.from(await resolved!.arrayBuffer()).toString(), "hello", ); } finally { URL.revokeObjectURL(url); } }, }); Deno.test({ name: "[node/buffer] resolveObjectURL returns undefined for revoked URL", fn() { const blob = new Blob(["hello"]); const url = URL.createObjectURL(blob); URL.revokeObjectURL(url); assertEquals(resolveObjectURL(url), undefined); }, }); Deno.test({ name: "[node/buffer] indexOf and includes work correctly", fn() { const buf = Buffer.from("Hello World"); assertEquals(buf.indexOf("World"), 6); assertEquals(buf.indexOf("World", 0, "utf8"), 6); assertEquals(buf.includes("Hello"), true); assertEquals(buf.indexOf(Buffer.from("World")), 6); }, }); Deno.test({ name: "[node/buffer] resolveObjectURL returns undefined for invalid inputs", fn() { assertEquals(resolveObjectURL("not a url"), undefined); assertEquals(resolveObjectURL("blob:nodedata:1:wrong"), undefined); // deno-lint-ignore no-explicit-any assertEquals(resolveObjectURL(undefined as any), undefined); // deno-lint-ignore no-explicit-any assertEquals(resolveObjectURL(1 as any), undefined); // deno-lint-ignore no-explicit-any assertEquals(resolveObjectURL({} as any), undefined); }, }); Deno.test({ name: "[node/buffer] transcode UTF-16LE to UTF-8 with odd-length input", fn() { // Odd-length: trailing byte is dropped (matches Node.js) const odd = Buffer.from([0x61, 0x00, 0x62]); assertEquals(transcode(odd, "utf16le", "utf8").toString(), "a"); // Even-length: normal case const even = Buffer.from([0x48, 0x00, 0x69, 0x00]); assertEquals(transcode(even, "utf16le", "utf8").toString(), "Hi"); // Empty buffer const empty = Buffer.alloc(0); assertEquals(transcode(empty, "utf16le", "utf8").toString(), ""); // Single byte (all trailing, dropped) const single = Buffer.from([0x41]); assertEquals(transcode(single, "utf16le", "utf8").toString(), ""); }, }); // Node's real Buffer has no _isBuffer marker; the npm `buffer` polyfill // (feross/buffer) sets it to true and libraries like bson use that to detect // a non-Node runtime and fall back to a Uint8Array codepath that breaks // mongodb SCRAM auth (denoland/deno#34468). Deno.test({ name: "[node/buffer] Buffer.prototype does not expose _isBuffer marker", fn() { // deno-lint-ignore no-explicit-any assertEquals((Buffer.prototype as any)._isBuffer, undefined); // deno-lint-ignore no-explicit-any assertEquals((Buffer.alloc(1) as any)._isBuffer, undefined); }, }); // Empty needle + negative end must clamp to 0, matching Node's // search_end = min(max(end, 0), haystack_length). Not covered by // upstream test-buffer-indexof.js Deno.test({ name: "[node/buffer] indexOf clamps negative end to 0 for empty needle", fn() { const buf = Buffer.from("abcabc"); assertEquals(buf.indexOf("", 0, -1), 0); assertEquals(buf.indexOf("", 0, -100), 0); assertEquals(buf.indexOf(Buffer.from(""), 0, -1), 0); }, }); Deno.test({ name: "[node/buffer] lastIndexOf clamps negative end to 0 for empty needle", fn() { const buf = Buffer.from("abcabc"); assertEquals(buf.lastIndexOf("", 5, -1), 0); assertEquals(buf.lastIndexOf(Buffer.from(""), 5, -1), 0); }, }); // UCS2/utf16le end must round down to an even boundary, matching // Node's `search_end &= ~1`. Not covered by upstream for any // ucs2/utf16le case that passes an explicit `end`. Deno.test({ name: "[node/buffer] indexOf rounds odd end down to nearest ucs2 code unit boundary", fn() { const ucs2buf = Buffer.from("abc", "ucs2"); // 6 bytes, 3 code units assertEquals(ucs2buf.indexOf("b", 0, 3, "ucs2"), -1); assertEquals(ucs2buf.indexOf("b", 0, 4, "ucs2"), 2); }, }); // A forward UCS2 search must align an odd byteOffset down to the code-unit // grid, matching Node's `offset / 2`. Not covered by upstream, which only // passes even (0) offsets for ucs2. Deno.test({ name: "[node/buffer] indexOf aligns odd ucs2 byteOffset down to code unit", fn() { assertEquals(Buffer.from("ab", "utf16le").indexOf("a", 1, "utf16le"), 0); assertEquals(Buffer.from("ba", "utf16le").indexOf("a", 1, "utf16le"), 2); assertEquals( Buffer.from("ab", "utf16le").includes("a", 1, "utf16le"), true, ); }, }); // A UCS2 needle with a trailing odd byte must be truncated to whole code // units, matching Node's `needle_length / 2`. Not covered by upstream, whose // ucs2 needles are all even-length strings. Deno.test({ name: "[node/buffer] indexOf truncates odd-length ucs2 needle to code units", fn() { const needle = Buffer.from([0x61, 0x00, 0xff]); // "a\0" + stray byte assertEquals( Buffer.from("ab", "utf16le").indexOf(needle, 0, "utf16le"), 0, ); }, }); // A fractional byteOffset must be truncated toward zero, matching Node reading // it as an int64 at the binding boundary. Not covered by upstream. Deno.test({ name: "[node/buffer] indexOf/lastIndexOf truncate fractional byteOffset", fn() { const buf = Buffer.from("abcabc"); assertEquals(Buffer.from("abc").indexOf(98, 0.5), 1); assertEquals(Buffer.from("abc").indexOf("b", 0.5), 1); assertEquals(buf.lastIndexOf("a", 4.9), 3); assertEquals(buf.lastIndexOf(0x61, 4.9), 3); }, });