diff options
author | 2023-03-02 17:36:47 -0800 | |
---|---|---|
committer | 2023-03-02 17:36:47 -0800 | |
commit | b469e5035161286abeb1a7726518d1afcc163a51 (patch) | |
tree | 2eb8c1e1e4d1adf726888b39d1c6f43795c65a1a | |
parent | 27c35791185bd85337e312e12c87d5c22d7f3a52 (diff) | |
download | bun-b469e5035161286abeb1a7726518d1afcc163a51.tar.gz bun-b469e5035161286abeb1a7726518d1afcc163a51.tar.zst bun-b469e5035161286abeb1a7726518d1afcc163a51.zip |
Add fs/promises tests and migrate fs.test.js to TypeScript (#2279)
-rw-r--r-- | packages/bun-types/bun.d.ts | 36 | ||||
-rw-r--r-- | packages/bun-types/fs.d.ts | 7 | ||||
-rw-r--r-- | packages/bun-types/fs/promises.d.ts | 37 | ||||
-rw-r--r-- | packages/bun-types/tests/fs.test-d.ts | 6 | ||||
-rw-r--r-- | test/bun.js/event-emitter.test.ts | 2 | ||||
-rw-r--r-- | test/bun.js/fs.test.ts (renamed from test/bun.js/fs.test.js) | 53 | ||||
-rw-r--r-- | test/bun.js/gc.ts (renamed from test/bun.js/gc.js) | 4 |
7 files changed, 103 insertions, 42 deletions
diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 8f020dcfc..fc3bcbdb1 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -395,7 +395,9 @@ declare module "bun" { stream?: boolean; }): void; - write(chunk: string | ArrayBufferView | ArrayBuffer): number; + write( + chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, + ): number; /** * Flush the internal buffer * @@ -534,7 +536,9 @@ declare module "bun" { * * If the file descriptor is not writable yet, the data is buffered. */ - write(chunk: string | ArrayBufferView | ArrayBuffer): number; + write( + chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, + ): number; /** * Flush the internal buffer, committing the data to disk or the pipe. */ @@ -650,38 +654,38 @@ declare module "bun" { * @param seed The seed to use. */ export const hash: (( - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number, ) => number | bigint) & Hash; interface Hash { wyhash: ( - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number, ) => number | bigint; crc32: ( - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number, ) => number | bigint; adler32: ( - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number, ) => number | bigint; cityHash32: ( - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number, ) => number | bigint; cityHash64: ( - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number, ) => number | bigint; murmur32v3: ( - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number, ) => number | bigint; murmur64v2: ( - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number, ) => number | bigint; } @@ -989,7 +993,7 @@ declare module "bun" { * */ send( - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, compress?: boolean, ): ServerWebSocketSendStatus; @@ -1101,7 +1105,7 @@ declare module "bun" { */ publish( topic: string, - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, compress?: boolean, ): ServerWebSocketSendStatus; @@ -1739,7 +1743,7 @@ declare module "bun" { */ publish( topic: string, - data: string | ArrayBufferView | ArrayBuffer, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, compress?: boolean, ): ServerWebSocketSendStatus; @@ -1944,7 +1948,7 @@ declare module "bun" { * @param level * @returns The previous level */ - gcAggressionLevel(level: 0 | 1 | 2): 0 | 1 | 2; + gcAggressionLevel(level?: 0 | 1 | 2): 0 | 1 | 2; } export const unsafe: unsafe; @@ -2474,7 +2478,7 @@ declare module "bun" { /** * The source code of the module */ - contents: string | ArrayBufferView | ArrayBuffer; + contents: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer; /** * The loader to use for this file * @@ -3349,7 +3353,7 @@ type TimeLike = string | number | Date; type StringOrBuffer = string | TypedArray | ArrayBufferLike; type PathLike = string | TypedArray | ArrayBufferLike | URL; type PathOrFileDescriptor = PathLike | number; -type NoParamCallback = VoidFunction; +type NoParamCallback = (err: ErrnoException | null) => void; type BufferEncoding = | "buffer" | "utf8" diff --git a/packages/bun-types/fs.d.ts b/packages/bun-types/fs.d.ts index 7e34d5873..14c5c1d1d 100644 --- a/packages/bun-types/fs.d.ts +++ b/packages/bun-types/fs.d.ts @@ -20,10 +20,11 @@ declare module "fs" { import * as stream from "stream"; import type { SystemError, ArrayBufferView } from "bun"; - interface ObjectEncodingOptions { encoding?: BufferEncoding | null | undefined; } + + const promises: Awaited<typeof import("fs/promises")>; type EncodingOption = | ObjectEncodingOptions | BufferEncoding @@ -1517,6 +1518,7 @@ declare module "fs" { * See the POSIX [`mkdir(2)`](http://man7.org/linux/man-pages/man2/mkdir.2.html) documentation for more details. * @since v0.0.67 */ + function mkdirSync( path: PathLike, options: MakeDirectoryOptions & { @@ -3930,6 +3932,5 @@ declare module "fs" { } declare module "node:fs" { - import * as fs from "fs"; - export = fs; + export * from "fs"; } diff --git a/packages/bun-types/fs/promises.d.ts b/packages/bun-types/fs/promises.d.ts index 164ef8db9..997896b01 100644 --- a/packages/bun-types/fs/promises.d.ts +++ b/packages/bun-types/fs/promises.d.ts @@ -9,7 +9,7 @@ */ declare module "fs/promises" { import { ArrayBufferView } from "bun"; - import { + import type { Stats, BigIntStats, StatOptions, @@ -25,6 +25,7 @@ declare module "fs/promises" { SimlinkType, Abortable, RmOptions, + RmDirOptions, } from "node:fs"; interface FlagAndOpenMode { @@ -677,9 +678,39 @@ declare module "fs/promises" { * @since v14.14.0 */ export function rm(path: PathLike, options?: RmOptions): Promise<void>; + + /** + * Asynchronously test whether or not the given path exists by checking with the file system. + * + * ```ts + * import { exists } from 'fs/promises'; + * + * const e = await exists('/etc/passwd'); + * e; // boolean + * ``` + */ + function exists(path: PathLike): Promise<boolean>; + + /** + * @deprecated Use `fs.promises.rm()` instead. + * + * Asynchronously remove a directory. + * + * ```ts + * import { rmdir } from 'fs/promises'; + * + * // remove a directory + * await rmdir('/tmp/mydir'); // Promise<void> + * ``` + * + * To remove a directory recursively, use `fs.promises.rm()` instead, with the `recursive` option set to `true`. + */ + function rmdir( + path: PathLike, + options?: Omit<RmDirOptions, "recursive">, + ): Promise<void>; } declare module "node:fs/promises" { - import * as fsPromises from "fs/promises"; - export = fsPromises; + export * from "fs/promises"; } diff --git a/packages/bun-types/tests/fs.test-d.ts b/packages/bun-types/tests/fs.test-d.ts new file mode 100644 index 000000000..1ef14a2f8 --- /dev/null +++ b/packages/bun-types/tests/fs.test-d.ts @@ -0,0 +1,6 @@ +import * as tsd from "tsd"; +import * as fs from "fs"; +import { exists } from "fs/promises"; + +tsd.expectType<Promise<boolean>>(exists("/etc/passwd")); +tsd.expectType<Promise<boolean>>(fs.promises.exists("/etc/passwd")); diff --git a/test/bun.js/event-emitter.test.ts b/test/bun.js/event-emitter.test.ts index cd1eaeaf2..2bb891778 100644 --- a/test/bun.js/event-emitter.test.ts +++ b/test/bun.js/event-emitter.test.ts @@ -150,7 +150,7 @@ test("EventEmitter GCs", () => { (function () { Bun.gc(true); - function EventEmitterSubclass() { + function EventEmitterSubclass(this: any) { EventEmitter.call(this); } diff --git a/test/bun.js/fs.test.js b/test/bun.js/fs.test.ts index ce5209c53..4c847d25a 100644 --- a/test/bun.js/fs.test.js +++ b/test/bun.js/fs.test.ts @@ -26,6 +26,9 @@ import fs, { Dirent, Stats, } from "node:fs"; + +import _promises from "node:fs/promises"; + import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -49,7 +52,7 @@ describe("copyFileSync", () => { it("should work for files < 128 KB", () => { const tempdir = `/tmp/fs.test.js/${Date.now()}/1234/hi`; expect(existsSync(tempdir)).toBe(false); - expect(tempdir.includes(mkdirSync(tempdir, { recursive: true }))).toBe(true); + expect(tempdir.includes(mkdirSync(tempdir, { recursive: true })!)).toBe(true); // that don't exist copyFileSync(import.meta.path, tempdir + "/copyFileSync.js"); @@ -67,7 +70,7 @@ describe("copyFileSync", () => { it("should work for files > 128 KB ", () => { const tempdir = `/tmp/fs.test.js/${Date.now()}-1/1234/hi`; expect(existsSync(tempdir)).toBe(false); - expect(tempdir.includes(mkdirSync(tempdir, { recursive: true }))).toBe(true); + expect(tempdir.includes(mkdirSync(tempdir, { recursive: true })!)).toBe(true); var buffer = new Int32Array(128 * 1024); for (let i = 0; i < buffer.length; i++) { buffer[i] = i % 256; @@ -92,7 +95,7 @@ describe("mkdirSync", () => { it("should create a directory", () => { const tempdir = `/tmp/fs.test.js/${Date.now()}/1234/hi`; expect(existsSync(tempdir)).toBe(false); - expect(tempdir.includes(mkdirSync(tempdir, { recursive: true }))).toBe(true); + expect(tempdir.includes(mkdirSync(tempdir, { recursive: true })!)).toBe(true); expect(existsSync(tempdir)).toBe(true); }); }); @@ -135,6 +138,7 @@ it("mkdtempSync, readdirSync, rmdirSync and unlinkSync with non-ascii", () => { }); it("mkdtempSync() empty name", () => { + // @ts-ignore-next-line const tempdir = mkdtempSync(); expect(existsSync(tempdir)).toBe(true); writeFileSync(tempdir + "/non-ascii-👍.txt", "hello"); @@ -188,7 +192,7 @@ it("readdirSync throws when given a file path", () => { try { readdirSync(import.meta.path); throw new Error("should not get here"); - } catch (exception) { + } catch (exception: any) { expect(exception.name).toBe("ENOTDIR"); } }); @@ -197,7 +201,7 @@ it("readdirSync throws when given a path that doesn't exist", () => { try { readdirSync(import.meta.path + "/does-not-exist/really"); throw new Error("should not get here"); - } catch (exception) { + } catch (exception: any) { expect(exception.name).toBe("ENOTDIR"); } }); @@ -206,7 +210,7 @@ it("readdirSync throws when given a file path with trailing slash", () => { try { readdirSync(import.meta.path + "/"); throw new Error("should not get here"); - } catch (exception) { + } catch (exception: any) { expect(exception.name).toBe("ENOTDIR"); } }); @@ -455,7 +459,7 @@ describe("stat", () => { try { statSync("/tmp/doesntexist"); throw "statSync should throw"; - } catch (e) { + } catch (e: any) { expect(e.code).toBe("ENOENT"); } }); @@ -499,8 +503,8 @@ describe("rmdir", () => { rmdir(path, err => { try { expect(err).toBeDefined(); - expect(err.code).toBe("EPERM"); - expect(err.message).toBe("Operation not permitted"); + expect(err!.code).toBe("EPERM"); + expect(err!.message).toBe("Operation not permitted"); expect(existsSync(path)).toBe(true); } catch (e) { return done(e); @@ -621,6 +625,7 @@ describe("fs.WriteStream", () => { }); it("should be constructable", () => { + // @ts-ignore-next-line const stream = new fs.WriteStream("test.txt"); expect(stream instanceof fs.WriteStream).toBe(true); }); @@ -630,6 +635,7 @@ describe("fs.WriteStream", () => { mkdirForce(pathToDir); const path = join(pathToDir, `fs-writestream-test.txt`); + // @ts-ignore-next-line const stream = new fs.WriteStream(path, { flags: "w+" }); stream.write("Test file written successfully"); stream.end(); @@ -645,6 +651,7 @@ describe("fs.WriteStream", () => { }); it("should work if re-exported by name", () => { + // @ts-ignore-next-line const stream = new WriteStream_("test.txt"); expect(stream instanceof WriteStream_).toBe(true); expect(stream instanceof WriteStreamStar_).toBe(true); @@ -652,6 +659,7 @@ describe("fs.WriteStream", () => { }); it("should work if re-exported by name, called without new", () => { + // @ts-ignore-next-line const stream = WriteStream_("test.txt"); expect(stream instanceof WriteStream_).toBe(true); expect(stream instanceof WriteStreamStar_).toBe(true); @@ -659,6 +667,7 @@ describe("fs.WriteStream", () => { }); it("should work if re-exported, as export * from ...", () => { + // @ts-ignore-next-line const stream = new WriteStreamStar_("test.txt"); expect(stream instanceof WriteStream_).toBe(true); expect(stream instanceof WriteStreamStar_).toBe(true); @@ -666,6 +675,7 @@ describe("fs.WriteStream", () => { }); it("should work if re-exported, as export * from..., called without new", () => { + // @ts-ignore-next-line const stream = WriteStreamStar_("test.txt"); expect(stream instanceof WriteStream_).toBe(true); expect(stream instanceof WriteStreamStar_).toBe(true); @@ -676,7 +686,7 @@ describe("fs.WriteStream", () => { const pathToDir = `${tmpdir()}/${Date.now()}`; mkdirForce(pathToDir); const path = join(pathToDir, `fs-writestream-re-exported-test.txt`); - + // @ts-ignore-next-line const stream = new WriteStream_(path, { flags: "w+" }); stream.write("Test file written successfully"); stream.end(); @@ -698,6 +708,7 @@ describe("fs.ReadStream", () => { }); it("should be constructable", () => { + // @ts-ignore-next-line const stream = new fs.ReadStream("test.txt"); expect(stream instanceof fs.ReadStream).toBe(true); }); @@ -711,7 +722,7 @@ describe("fs.ReadStream", () => { encoding: "utf8", flag: "w+", }); - + // @ts-ignore-next-line const stream = new fs.ReadStream(path); stream.setEncoding("utf8"); stream.on("error", e => { @@ -731,6 +742,7 @@ describe("fs.ReadStream", () => { }); it("should work if re-exported by name", () => { + // @ts-ignore-next-line const stream = new ReadStream_("test.txt"); expect(stream instanceof ReadStream_).toBe(true); expect(stream instanceof ReadStreamStar_).toBe(true); @@ -738,6 +750,7 @@ describe("fs.ReadStream", () => { }); it("should work if re-exported by name, called without new", () => { + // @ts-ignore-next-line const stream = ReadStream_("test.txt"); expect(stream instanceof ReadStream_).toBe(true); expect(stream instanceof ReadStreamStar_).toBe(true); @@ -745,6 +758,7 @@ describe("fs.ReadStream", () => { }); it("should work if re-exported as export * from ...", () => { + // @ts-ignore-next-line const stream = new ReadStreamStar_("test.txt"); expect(stream instanceof ReadStreamStar_).toBe(true); expect(stream instanceof ReadStream_).toBe(true); @@ -752,6 +766,7 @@ describe("fs.ReadStream", () => { }); it("should work if re-exported as export * from ..., called without new", () => { + // @ts-ignore-next-line const stream = ReadStreamStar_("test.txt"); expect(stream instanceof ReadStreamStar_).toBe(true); expect(stream instanceof ReadStream_).toBe(true); @@ -768,6 +783,7 @@ describe("fs.ReadStream", () => { flag: "w+", }); + // @ts-ignore-next-line const stream = new ReadStream_(path); stream.setEncoding("utf8"); stream.on("error", e => { @@ -812,7 +828,7 @@ describe("createWriteStream", () => { try { stream.write(null); expect(() => {}).toThrow(Error); - } catch (exception) { + } catch (exception: any) { expect(exception.code).toBe("ERR_STREAM_NULL_VALUES"); } }); @@ -820,12 +836,13 @@ describe("createWriteStream", () => { it("writing null throws ERR_STREAM_NULL_VALUES (objectMode: true)", async () => { const path = `/tmp/fs.test.js/${Date.now()}.createWriteStreamNulls.txt`; const stream = createWriteStream(path, { + // @ts-ignore-next-line objectMode: true, }); try { stream.write(null); expect(() => {}).toThrow(Error); - } catch (exception) { + } catch (exception: any) { expect(exception.code).toBe("ERR_STREAM_NULL_VALUES"); } }); @@ -836,7 +853,7 @@ describe("createWriteStream", () => { try { stream.write(false); expect(() => {}).toThrow(Error); - } catch (exception) { + } catch (exception: any) { expect(exception.code).toBe("ERR_INVALID_ARG_TYPE"); } }); @@ -844,12 +861,13 @@ describe("createWriteStream", () => { it("writing false throws ERR_INVALID_ARG_TYPE (objectMode: true)", async () => { const path = `/tmp/fs.test.js/${Date.now()}.createWriteStreamFalse.txt`; const stream = createWriteStream(path, { + // @ts-ignore-next-line objectMode: true, }); try { stream.write(false); expect(() => {}).toThrow(Error); - } catch (exception) { + } catch (exception: any) { expect(exception.code).toBe("ERR_INVALID_ARG_TYPE"); } }); @@ -893,7 +911,7 @@ describe("fs/promises", () => { for (const args of fizz) { try { // check it doens't segfault when called with invalid arguments - await promises.readdir(...args); + await promises.readdir(...(args as [any, ...any[]])); } catch (e) { // check that producing the error doesn't cause any crashes Bun.inspect(e); @@ -909,7 +927,7 @@ describe("fs/promises", () => { try { await rmdir(path); expect(() => {}).toThrow(); - } catch (err) { + } catch (err: any) { expect(err.code).toBe("ENOTDIR"); // expect(err.message).toBe("Operation not permitted"); expect(await exists(path)).toBe(true); @@ -992,6 +1010,7 @@ it("fs.Stats", () => { it("repro 1516: can use undefined/null to specify default flag", () => { const path = "/tmp/repro_1516.txt"; writeFileSync(path, "b", { flag: undefined }); + // @ts-ignore-next-line expect(readFileSync(path, { encoding: "utf8", flag: null })).toBe("b"); rmSync(path); }); diff --git a/test/bun.js/gc.js b/test/bun.js/gc.ts index 3f9678f92..b9d80116d 100644 --- a/test/bun.js/gc.js +++ b/test/bun.js/gc.ts @@ -1,5 +1,5 @@ -export function gc() { - Bun.gc(true); +export function gc(force: boolean = true) { + Bun.gc(force); } // we must ensure that finalizers are run |