// 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 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] 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);
  },
});
