Repository: denoland/deno
Pull request: fix(ext/node): fix `Buffer.inspect` compatiblity

Enables `parallel/test-buffer-inspect.js`

Towards #29589 

Changed files:
filename: ext/node/polyfills/internal/buffer.mjs
patch: @@ -15,6 +15,7 @@ const {
   ArrayBufferPrototypeGetDetached,
   ArrayIsArray,
   ArrayPrototypeSlice,
+  ArrayPrototypeForEach,
   BigInt,
   DataViewPrototypeGetByteLength,
   Float32Array,
@@ -36,6 +37,7 @@ const {
   String,
   StringFromCharCode,
   StringPrototypeCharCodeAt,
+  StringPrototypeSlice,
   StringPrototypeIncludes,
   StringPrototypeReplace,
   StringPrototypeToLowerCase,
@@ -80,7 +82,13 @@ import {
   hexToBytes,
   utf16leToBytes,
 } from "ext:deno_node/internal_binding/_utils.ts";
+import { inspect as utilInspect } from "ext:deno_node/internal/util/inspect.mjs";
 import { normalizeEncoding } from "ext:deno_node/internal/util.mjs";
+import {
+  ALL_PROPERTIES,
+  getOwnNonIndexProperties,
+  ONLY_ENUMERABLE,
+} from "ext:deno_node/internal_binding/util.ts";
 import {
   validateBuffer,
   validateInteger,
@@ -715,7 +723,7 @@ const SPACER_PATTERN = new SafeRegExp(/(.{2})/g);
 
 Buffer.prototype[customInspectSymbol] =
   Buffer.prototype.inspect =
-    function inspect() {
+    function inspect(_, ctx) {
       let str = "";
       str = StringPrototypeTrim(
         StringPrototypeReplace(
@@ -729,6 +737,32 @@ Buffer.prototype[customInspectSymbol] =
         const remaining = this.length - INSPECT_MAX_BYTES_;
         str += ` ... ${remaining} more byte${remaining > 1 ? "s" : ""}`;
       }
+      // Inspect special properties as well, if possible.
+      if (ctx) {
+        let extras = false;
+        const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE;
+        const obj = { __proto__: null };
+        ArrayPrototypeForEach(getOwnNonIndexProperties(this, filter), (key) => {
+          extras = true;
+          obj[key] = this[key];
+        });
+        if (extras) {
+          if (this.length !== 0) {
+            str += ", ";
+          }
+          // '[Object: null prototype] {'.length === 26
+          // This is guarded with a test.
+          str += StringPrototypeSlice(
+            utilInspect(obj, {
+              ...ctx,
+              breakLength: Infinity,
+              compact: true,
+            }),
+            27,
+            -2,
+          );
+        }
+      }
       return "<Buffer " + str + ">";
     };
 

filename: ext/node/polyfills/internal_binding/util.ts
patch: @@ -98,7 +98,7 @@ export function getOwnNonIndexProperties(
     ...Object.getOwnPropertySymbols(obj),
   ];
 
-  if (Array.isArray(obj)) {
+  if (Array.isArray(obj) || ArrayBuffer.isView(obj)) {
     allProperties = allProperties.filter((k) => !isArrayIndex(k));
   }
 

filename: tests/node_compat/config.jsonc
patch: @@ -293,6 +293,7 @@
       "test-buffer-includes.js",
       "test-buffer-indexof.js",
       "test-buffer-inheritance.js",
+      "test-buffer-inspect.js",
       "test-buffer-isascii.js",
       "test-buffer-isencoding.js",
       "test-buffer-isutf8.js",

filename: tests/node_compat/runner/TODO.md
patch: @@ -1,7 +1,7 @@
 <!-- deno-fmt-ignore-file -->
 # Remaining Node Tests
 
-1192 tests out of 3993 have been ported from Node 23.9.0 (29.85% ported, 70.75% remaining).
+1194 tests out of 3993 have been ported from Node 23.9.0 (29.90% ported, 70.70% remaining).
 
 NOTE: This file should not be manually edited. Please edit `tests/node_compat/config.json` and run `deno task setup` in `tests/node_compat/runner` dir instead.
 
@@ -283,7 +283,6 @@ NOTE: This file should not be manually edited. Please edit `tests/node_compat/co
 - [parallel/test-bootstrap-modules.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-bootstrap-modules.js)
 - [parallel/test-broadcastchannel-custom-inspect.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-broadcastchannel-custom-inspect.js)
 - [parallel/test-buffer-constructor-node-modules-paths.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-buffer-constructor-node-modules-paths.js)
-- [parallel/test-buffer-inspect.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-buffer-inspect.js)
 - [parallel/test-buffer-prototype-inspect.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-buffer-prototype-inspect.js)
 - [parallel/test-c-ares.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-c-ares.js)
 - [parallel/test-child-process-advanced-serialization-largebuffer.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-child-process-advanced-serialization-largebuffer.js)

filename: tests/node_compat/test/parallel/test-buffer-inspect.js
patch: @@ -0,0 +1,77 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 23.9.0
+// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const util = require('util');
+const buffer = require('buffer');
+
+buffer.INSPECT_MAX_BYTES = 2;
+
+let b = Buffer.allocUnsafe(4);
+b.fill('1234');
+
+let s = buffer.SlowBuffer(4);
+s.fill('1234');
+
+let expected = '<Buffer 31 32 ... 2 more bytes>';
+
+assert.strictEqual(util.inspect(b), expected);
+assert.strictEqual(util.inspect(s), expected);
+
+b = Buffer.allocUnsafe(2);
+b.fill('12');
+
+s = buffer.SlowBuffer(2);
+s.fill('12');
+
+expected = '<Buffer 31 32>';
+
+assert.strictEqual(util.inspect(b), expected);
+assert.strictEqual(util.inspect(s), expected);
+
+buffer.INSPECT_MAX_BYTES = Infinity;
+
+assert.strictEqual(util.inspect(b), expected);
+assert.strictEqual(util.inspect(s), expected);
+
+b.inspect = undefined;
+b.prop = new Uint8Array(0);
+assert.strictEqual(
+  util.inspect(b),
+  '<Buffer 31 32, inspect: undefined, prop: Uint8Array(0) []>'
+);
+
+b = Buffer.alloc(0);
+b.prop = 123;
+
+assert.strictEqual(
+  util.inspect(b),
+  '<Buffer prop: 123>'
+);