diff options
author | 2023-08-17 20:56:52 -0700 | |
---|---|---|
committer | 2023-08-17 20:56:52 -0700 | |
commit | 6fd0043f6bf766cc488a88339059e8879fa07161 (patch) | |
tree | d5289bcaf0880a3bf1e2f0b1c681aff93188fe51 /test | |
parent | 0424fd8f6e7549ed779788006acdc97a8467e287 (diff) | |
download | bun-6fd0043f6bf766cc488a88339059e8879fa07161.tar.gz bun-6fd0043f6bf766cc488a88339059e8879fa07161.tar.zst bun-6fd0043f6bf766cc488a88339059e8879fa07161.zip |
Add `util.inspect.custom` support to `util.inspect/Bun.inspect/console.log` (#4194)
* start work on util.inspect.custom
* asdf
* finish util inspect custom inspect
* inspect
* fix tests
* revert
* tidy
* revert
* oops
* test
* fix issues
Diffstat (limited to 'test')
-rw-r--r-- | test/js/bun/util/inspect.test.js | 44 | ||||
-rw-r--r-- | test/js/node/util/bun-inspect.test.ts | 23 | ||||
-rw-r--r-- | test/js/node/util/custom-inspect.test.js | 155 |
3 files changed, 199 insertions, 23 deletions
diff --git a/test/js/bun/util/inspect.test.js b/test/js/bun/util/inspect.test.js index 4d5165543..6ae9e9816 100644 --- a/test/js/bun/util/inspect.test.js +++ b/test/js/bun/util/inspect.test.js @@ -94,12 +94,12 @@ it("utf16 property name", () => { }); it("latin1", () => { - expect(Bun.inspect("English")).toBe("English"); - expect(Bun.inspect("Français")).toBe("Français"); - expect(Bun.inspect("Ελληνική")).toBe("Ελληνική"); - expect(Bun.inspect("日本語")).toBe("日本語"); - expect(Bun.inspect("Emoji😎")).toBe("Emoji😎"); - expect(Bun.inspect("Français / Ελληνική")).toBe("Français / Ελληνική"); + expect(Bun.inspect("English")).toBe('"English"'); + expect(Bun.inspect("Français")).toBe('"Français"'); + expect(Bun.inspect("Ελληνική")).toBe('"Ελληνική"'); + expect(Bun.inspect("日本語")).toBe('"日本語"'); + expect(Bun.inspect("Emoji😎")).toBe('"Emoji😎"'); + expect(Bun.inspect("Français / Ελληνική")).toBe('"Français / Ελληνική"'); }); it("Request object", () => { @@ -213,12 +213,11 @@ it("jsx with fragment", () => { it("inspect", () => { expect(Bun.inspect(new TypeError("what")).includes("TypeError: what")).toBe(true); - expect("hi").toBe("hi"); + expect(Bun.inspect("hi")).toBe('"hi"'); expect(Bun.inspect(1)).toBe("1"); expect(Bun.inspect(NaN)).toBe("NaN"); expect(Bun.inspect(Infinity)).toBe("Infinity"); expect(Bun.inspect(-Infinity)).toBe("-Infinity"); - expect(Bun.inspect(1, "hi")).toBe("1 hi"); expect(Bun.inspect([])).toBe("[]"); expect(Bun.inspect({})).toBe("{}"); expect(Bun.inspect({ hello: 1 })).toBe("{\n hello: 1\n}"); @@ -229,7 +228,7 @@ it("inspect", () => { while (str.length < 4096) { str += "123"; } - expect(Bun.inspect(str)).toBe(str); + expect(Bun.inspect(str)).toBe('"' + str + '"'); // expect(Bun.inspect(new Headers())).toBe("Headers (0 KB) {}"); expect(Bun.inspect(new Response()).length > 0).toBe(true); // expect( @@ -277,18 +276,15 @@ describe("latin1 supplemental", () => { it(`latin1 (input) \"${input}\" ${output}`, () => { expect(Bun.inspect(input)).toBe(output); }); - it(`latin1 (output) \"${output}\"`, () => { - expect(Bun.inspect(output)).toBe(output); - }); - // this test is failing: - // it(`latin1 (property key)`, () => { - // expect( - // Object.keys({ - // ä: 1, - // })[0].codePointAt(0), - // ).toBe(228); - // }); } + // this test is failing: + it(`latin1 (property key)`, () => { + expect( + Object.keys({ + ä: 1, + })[0].codePointAt(0), + ).toBe(228); + }); }); const fixture = [ @@ -329,7 +325,9 @@ describe("crash testing", () => { for (let input of fixture) { it(`inspecting "${input.toString().slice(0, 20).replaceAll("\n", "\\n")}" doesn't crash`, async () => { try { + console.log("asked" + input.toString().slice(0, 20).replaceAll("\n", "\\n")); Bun.inspect(await input()); + console.log("who"); } catch (e) { // this can throw its fine } @@ -338,7 +336,7 @@ describe("crash testing", () => { }); it("possibly formatted emojis log", () => { - expect(Bun.inspect("✔", "hey")).toBe("✔ hey"); + expect(Bun.inspect("✔")).toBe('"✔"'); }); it("new Date(..)", () => { @@ -352,8 +350,8 @@ it("new Date(..)", () => { } expect(Bun.inspect(new Date("March 27, 2023 " + hour + ":54:00"))).toBe("2023-03-27T09:54:00.000Z"); expect(Bun.inspect(new Date("2023-03-27T" + hour + ":54:00"))).toBe("2023-03-27T09:54:00.000Z"); - expect(Bun.inspect(new Date(2023, 02, 27, -offset))).toBe("2023-03-27T00:00:00.000Z"); - expect(Bun.inspect(new Date(2023, 02, 27, 09 - offset, 54, 0))).toBe("2023-03-27T09:54:00.000Z"); + expect(Bun.inspect(new Date(2023, 2, 27, -offset))).toBe("2023-03-27T00:00:00.000Z"); + expect(Bun.inspect(new Date(2023, 2, 27, 9 - offset, 54, 0))).toBe("2023-03-27T09:54:00.000Z"); expect(Bun.inspect(new Date("1679911059000"))).toBe("Invalid Date"); expect(Bun.inspect(new Date("hello world"))).toBe("Invalid Date"); diff --git a/test/js/node/util/bun-inspect.test.ts b/test/js/node/util/bun-inspect.test.ts new file mode 100644 index 000000000..308f275b9 --- /dev/null +++ b/test/js/node/util/bun-inspect.test.ts @@ -0,0 +1,23 @@ +import { describe, it, expect } from "bun:test"; + +describe("Bun.inspect", () => { + it("depth < 0 throws", () => { + expect(() => Bun.inspect({}, { depth: -1 })).toThrow(); + expect(() => Bun.inspect({}, { depth: -13210 })).toThrow(); + }); + it("depth = Infinity works", () => { + function createRecursiveObject(n: number): any { + if (n === 0) return { hi: true }; + return { a: createRecursiveObject(n - 1) }; + } + + const obj = createRecursiveObject(1000); + + expect(Bun.inspect(obj, { depth: Infinity })).toContain("hi"); + // this gets converted to u16, which if just truncating, will turn into 0 + expect(Bun.inspect(obj, { depth: 0x0fff0000 })).toContain("hi"); + }); + it("depth = 0", () => { + expect(Bun.inspect({ a: { b: { c: { d: 1 } } } }, { depth: 0 })).toEqual("{\n a: [Object ...]\n}"); + }); +}); diff --git a/test/js/node/util/custom-inspect.test.js b/test/js/node/util/custom-inspect.test.js new file mode 100644 index 000000000..06cad262a --- /dev/null +++ b/test/js/node/util/custom-inspect.test.js @@ -0,0 +1,155 @@ +// this file is compatible with jest to test node.js' util.inspect as well as bun's + +const util = require("util"); + +test("util.inspect.custom exists", () => { + expect(util.inspect.custom).toEqual(Symbol.for("nodejs.util.inspect.custom")); +}); + +const customSymbol = util.inspect.custom; + +for (const [name, inspect] of process.versions.bun + ? [ + ["util.inspect", util.inspect], + ["Bun.inspect", Bun.inspect], + ] + : [["util.inspect", util.inspect]]) { + test(name + " calls inspect.custom", () => { + const obj = { + [customSymbol]() { + return "42"; + }, + }; + + expect(inspect(obj)).toBe("42"); + }); + + test(name + " calls inspect.custom recursivly", () => { + const obj = { + [customSymbol]() { + return { + [customSymbol]() { + return "42"; + }, + }; + }, + }; + + expect(inspect(obj)).toBe("42"); + }); + + test(name + " calls inspect.custom recursivly nested", () => { + const obj = { + [customSymbol]() { + return { + prop: { + [customSymbol]() { + return "42"; + }, + }, + }; + }, + }; + + expect(inspect(obj).replace(/\s/g, "")).toBe("{prop:42}"); + }); + + test(name + " calls inspect.custom recursivly nested 2", () => { + const obj = { + prop: { + [customSymbol]() { + return { + [customSymbol]() { + return "42"; + }, + }; + }, + }, + }; + + expect(inspect(obj).replace(/\s/g, "")).toBe("{prop:42}"); + }); + + test(name + " calls inspect.custom with valid options", () => { + const obj = { + [customSymbol](depth, options, inspect) { + expect(this === obj).toBe(true); + expect(inspect).toBe(util.inspect); + expect(options.stylize).toBeDefined(); + expect(depth).toBeDefined(2); + return "good"; + }, + }; + + expect(inspect(obj).replace(/\s/g, "")).toBe("good"); + }); + + test(name + " stylize function works without color", () => { + const obj = { + [customSymbol](depth, options, inspect) { + expect(options.stylize).toBeDefined(); + expect(options.stylize("foo", "whatever")).toBe("foo"); + expect(options.stylize("hello", "string")).toBe("hello"); + return "good"; + }, + }; + + expect(inspect(obj).replace(/\s/g, "")).toBe("good"); + }); + + test(name + " stylize function works with color", () => { + const obj = { + [customSymbol](depth, options, inspect) { + expect(options.stylize).toBeDefined(); + expect(options.stylize("foo", "invalid")).toBe("foo"); + expect(options.stylize("foo", "boolean")).toBe("\u001b[33mfoo\u001b[39m"); + expect(options.stylize("hello", "string")).toBe("\u001b[32mhello\u001b[39m"); + return "good"; + }, + }; + + expect(inspect(obj, { colors: true }).replace(/\s/g, "")).toBe("good"); + }); + + test(name + " stylize function gives correct depth", () => { + const obj = { + [customSymbol](depth, options, inspect) { + return [depth, options.depth]; + }, + }; + expect(inspect(obj, { depth: 3 }).replace(/\s/g, "")).toBe("[3,3]"); + }); + test(name + " stylize function gives correct depth", () => { + const obj = { + prop: { + [customSymbol](depth, options, inspect) { + return [depth, options.depth]; + }, + }, + }; + expect(inspect(obj, { depth: 3 }).replace(/\s/g, "")).toBe("{prop:[2,3]}"); + }); + test(name + " non-callable does not get called", () => { + const obj = { + [customSymbol]: 512, + }; + expect(inspect(obj, { depth: 3 }).replace(/\s/g, "")).toBe("{[Symbol(nodejs.util.inspect.custom)]:512}"); + }); + + const exceptions = [new Error("don't crash!"), 42]; + + test.each(exceptions)(name + " handles exceptions %s", err => { + const obj = { + [customSymbol]() { + throw err; + }, + }; + + if (Bun.inspect === inspect) { + // make sure this doesnt crash + expect(inspect(obj)).toBeString(); + } else { + expect(() => inspect(obj)).toThrow(); + } + }); +} |