Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/js/node/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,7 @@ class Dir {
}

read(cb?: Callback<[entry: DirentType | null]>): any {
if (!$isUndefinedOrNull(cb)) {
if (cb !== undefined) {
Comment thread
robobun marked this conversation as resolved.
Resolved
validateFunction(cb, "callback");
cb = guardCallback(cb);
// node's callback overload returns undefined (like close(cb) above)
Expand Down Expand Up @@ -1231,7 +1231,7 @@ class Dir {
}

close(cb?: Callback) {
if (!$isUndefinedOrNull(cb)) {
if (cb !== undefined) {
validateFunction(cb, "callback");
cb = guardCallback(cb);
settleCallbackWithNull(this.close()!, cb);
Expand Down
30 changes: 29 additions & 1 deletion test/js/node/fs/dir.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "bun:test";
import { tempDir } from "harness";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
Expand Down Expand Up @@ -72,8 +73,12 @@ describe("fs.Dir", () => {
});

describe("reading from the directory", () => {
it.each([0, 1, false, "foo", {}])("throws if passed a non-function callback (%p)", badCb => {
it.each([null, 0, 1, false, "foo", {}])("throws if passed a non-function callback (%p)", badCb => {
// toThrow() also takes a rejected promise. toThrowWithCode() takes only a throw from the call.
expect(() => dir.read(badCb as any)).toThrowWithCode(TypeError, "ERR_INVALID_ARG_TYPE");
expect(() => dir.read(badCb as any)).toThrow(/The "callback" argument must be of type function/);
// No read started: a read in flight makes readSync() throw ERR_DIR_CONCURRENT_OPERATION.
expect(dir.readSync()).toBeNull();
Comment thread
robobun marked this conversation as resolved.
Resolved
});

it("it can be read synchronously, even though no entries exist", () => {
Expand All @@ -99,6 +104,13 @@ describe("fs.Dir", () => {
});
}); // </reading from the directory>

it.each([null, 0, 1, false, "foo", {}])("close throws if passed a non-function callback (%p)", badCb => {
expect(() => dir.close(badCb as any)).toThrowWithCode(TypeError, "ERR_INVALID_ARG_TYPE");
expect(() => dir.close(badCb as any)).toThrow(/The "callback" argument must be of type function/);
// The directory is still open.
expect(dir.closeSync()).toBeUndefined();
});

it("can be closed asynchronously", async () => {
const actual = await dir.close();
expect(actual).toBeUndefined();
Expand Down Expand Up @@ -128,13 +140,29 @@ describe("fs.Dir", () => {
expect(() => dir.close()).toThrow("Directory handle was closed");
});

it("close checks the callback before the closed handle", () => {
expect(() => dir.close(null as any)).toThrowWithCode(TypeError, "ERR_INVALID_ARG_TYPE");
expect(() => dir.close(null as any)).toThrow(/The "callback" argument must be of type function/);
});

it("attempts to read will throw", () => {
expect(() => dir.readSync()).toThrow("Directory handle was closed");
expect(() => dir.read()).toThrow("Directory handle was closed");
Comment thread
robobun marked this conversation as resolved.
Resolved
});
}); // </when closed>
}); // </when an empty directory is opened>
}); // </given an empty temp directory>

it("a read with a non-function callback takes no entry", () => {
using tmp = tempDir("dir-read-invalid-callback", { "a.txt": "", "b.txt": "" });
using dir = fs.opendirSync(String(tmp));
// The first read loads both entries.
const first = dir.readSync();
expect(() => dir.read(null as any)).toThrowWithCode(TypeError, "ERR_INVALID_ARG_TYPE");
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
const second = dir.readSync();
expect([first?.name, second?.name].sort()).toEqual(["a.txt", "b.txt"]);
expect(dir.readSync()).toBeNull();
});
}); // </fs.Dir>

describe("fs.opendir async validation", () => {
Expand Down
Loading