import assert from "node:assert"; import { describe, test } from "node:test"; import { ObjectTree } from "../src/internal.js"; import * as symbols from "../src/symbols.js"; import * as utilities from "../src/utilities.js"; describe("utilities", () => { test("box returns a boxed value", () => { const string = "string"; const stringObject = utilities.box(string); assert(stringObject instanceof String); assert.equal(stringObject, string); const number = 1; const numberObject = utilities.box(number); assert(numberObject instanceof Number); assert.equal(numberObject, number); const boolean = true; const booleanObject = utilities.box(boolean); assert(booleanObject instanceof Boolean); assert.equal(booleanObject, boolean); const object = {}; const boxedObject = utilities.box(object); assert.equal(boxedObject, object); }); test("getRealmObjectPrototype returns the object's root prototype", () => { const object = {}; const proto = utilities.getRealmObjectPrototype(object); assert.equal(proto, Object.prototype); }); test("isPlainObject returns true if the object is a plain object", () => { assert.equal(utilities.isPlainObject({}), true); assert.equal(utilities.isPlainObject(new Object()), true); assert.equal(utilities.isPlainObject(Object.create(null)), true); class Foo {} assert.equal(utilities.isPlainObject(new Foo()), false); }); test("keysFromPath() returns the keys from a slash-separated path", () => { assert.deepEqual(utilities.keysFromPath(""), []); assert.deepEqual(utilities.keysFromPath("/"), []); assert.deepEqual(utilities.keysFromPath("a/b/c"), ["a/", "b/", "c"]); assert.deepEqual(utilities.keysFromPath("a/b/c/"), ["a/", "b/", "c/"]); assert.deepEqual(utilities.keysFromPath("/foo/"), ["foo/"]); assert.deepEqual(utilities.keysFromPath("a///b"), ["a/", "b"]); }); test("naturalOrder compares strings in natural order", () => { const strings = ["file10", "file1", "file9"]; strings.sort(utilities.naturalOrder); assert.deepEqual(strings, ["file1", "file9", "file10"]); }); test("pathFromKeys() returns a slash-separated path from keys", () => { assert.equal(utilities.pathFromKeys([]), ""); assert.equal(utilities.pathFromKeys(["a", "b", "c"]), "a/b/c"); assert.equal(utilities.pathFromKeys(["a/", "b/", "c"]), "a/b/c"); }); test("pipeline applies a series of functions to a value", async () => { const addOne = (n) => n + 1; const double = (n) => n * 2; const square = (n) => n * n; const result = await utilities.pipeline(1, addOne, double, square); assert.equal(result, 16); }); test("setParent sets a child's parent", () => { const parent = new ObjectTree({}); // Set [symbols.parent] on a plain object. const object = {}; utilities.setParent(object, parent); assert.equal(object[symbols.parent], parent); // Leave [symbols.parent] alone if it's already set. const childWithParent = { [symbols.parent]: "parent", }; utilities.setParent(childWithParent, parent); assert.equal(childWithParent[symbols.parent], "parent"); // Set `parent` on a tree. const tree = new ObjectTree({}); utilities.setParent(tree, parent); assert.equal(tree.parent, parent); // Leave `parent` alone if it's already set. const treeWithParent = new ObjectTree({}); treeWithParent.parent = "parent"; utilities.setParent(treeWithParent, parent); assert.equal(treeWithParent.parent, "parent"); }); test("toPlainValue returns the plainest representation of an object", async () => { class User { constructor(name) { this.name = name; } } assert.equal(await utilities.toPlainValue(1), 1); assert.equal(await utilities.toPlainValue("string"), "string"); assert.deepEqual(await utilities.toPlainValue({ a: 1 }), { a: 1 }); assert.equal( await utilities.toPlainValue(new TextEncoder().encode("bytes")), "bytes" ); // ArrayBuffer with non-printable characters should be returned as base64 assert.equal( await utilities.toPlainValue(new Uint8Array([1, 2, 3]).buffer), "AQID" ); assert.equal(await utilities.toPlainValue(async () => "result"), "result"); assert.deepEqual(await utilities.toPlainValue(new User("Alice")), { name: "Alice", }); }); test("toString returns the value of an object's `toString` method", () => { const object = { toString: () => "text", }; assert.equal(utilities.toString(object), "text"); }); test("toString returns null for an object with no useful `toString`", () => { const object = {}; assert.equal(utilities.toString(object), null); }); test("toString decodes an ArrayBuffer as UTF-8", () => { const arrayBuffer = new TextEncoder().encode("text").buffer; assert.equal(utilities.toString(arrayBuffer), "text"); }); });