/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
tests/unit_node/_fs/_fs_dir_test.ts
289 строк
8 KB
sijie-Z
fix: throw ERR_DIR_CLOSED on use-after-close in Dir (#34910)
07 июн 2026, 12:15
Не верифицирован
07 июн 2026, 12:15
d0113ee
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. import { assert, assertEquals, fail } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { Dir as DirOrig, type Dirent } from "node:fs"; // deno-lint-ignore no-explicit-any const Dir = DirOrig as any; Deno.test({ name: "Closing current directory with callback is successful", fn() { let calledBack = false; // deno-lint-ignore no-explicit-any new Dir(".").close((valOrErr: any) => { assert(!valOrErr); calledBack = true; }); assert(calledBack); }, }); Deno.test({ name: "Closing current directory without callback returns void Promise", async fn() { await new Dir(".").close(); }, }); Deno.test({ name: "Closing current directory synchronously works", fn() { new Dir(".").closeSync(); }, }); Deno.test({ name: "Path is correctly returned", fn() { assertEquals(new Dir("std/node").path, "std/node"); const enc: Uint8Array = new TextEncoder().encode("std/node"); assertEquals(new Dir(enc).path, "std/node"); }, }); Deno.test({ name: "read returns null for empty directory", async fn() { const testDir: string = Deno.makeTempDirSync(); try { const file: Dirent | null = await new Dir(testDir).read(); assert(file === null); let calledBack = false; const fileFromCallback: Dirent | null = await new Dir( testDir, // deno-lint-ignore no-explicit-any ).read((err: any, res: Dirent) => { assert(res === null); assert(err === null); calledBack = true; }); assert(fileFromCallback === null); assert(calledBack); assertEquals(new Dir(testDir).readSync(), null); } finally { Deno.removeSync(testDir); } }, }); Deno.test({ name: "Async read returns one file at a time", async fn() { const testDir: string = Deno.makeTempDirSync(); const f1 = Deno.createSync(testDir + "/foo.txt"); f1.close(); const f2 = Deno.createSync(testDir + "/bar.txt"); f2.close(); try { let secondCallback = false; const dir = new Dir(testDir); const firstRead: Dirent | null = await dir.read(); const secondRead: Dirent | null = await dir.read( // deno-lint-ignore no-explicit-any (_err: any, secondResult: Dirent) => { assert( secondResult.name === "bar.txt" || secondResult.name === "foo.txt", ); secondCallback = true; }, ); const thirdRead: Dirent | null = await dir.read(); const fourthRead: Dirent | null = await dir.read(); if (firstRead?.name === "foo.txt") { assertEquals(secondRead?.name, "bar.txt"); } else if (firstRead?.name === "bar.txt") { assertEquals(secondRead?.name, "foo.txt"); } else { fail("File not found during read"); } assert(secondCallback); assert(thirdRead === null); assert(fourthRead === null); } finally { Deno.removeSync(testDir, { recursive: true }); } }, }); Deno.test({ name: "Sync read returns one file at a time", fn() { const testDir: string = Deno.makeTempDirSync(); const f1 = Deno.createSync(testDir + "/foo.txt"); f1.close(); const f2 = Deno.createSync(testDir + "/bar.txt"); f2.close(); try { const dir = new Dir(testDir); const firstRead: Dirent | null = dir.readSync(); const secondRead: Dirent | null = dir.readSync(); const thirdRead: Dirent | null = dir.readSync(); const fourthRead: Dirent | null = dir.readSync(); if (firstRead?.name === "foo.txt") { assertEquals(secondRead?.name, "bar.txt"); } else if (firstRead?.name === "bar.txt") { assertEquals(secondRead?.name, "foo.txt"); } else { fail("File not found during read"); } assert(thirdRead === null); assert(fourthRead === null); } finally { Deno.removeSync(testDir, { recursive: true }); } }, }); Deno.test({ name: "Async iteration over existing directory", async fn() { const testDir: string = Deno.makeTempDirSync(); const f1 = Deno.createSync(testDir + "/foo.txt"); f1.close(); const f2 = Deno.createSync(testDir + "/bar.txt"); f2.close(); try { const dir = new Dir(testDir); const results: Array<string | null> = []; for await (const file of dir[Symbol.asyncIterator]()) { results.push(file.name); } assert(results.length === 2); assert(results.includes("foo.txt")); assert(results.includes("bar.txt")); } finally { Deno.removeSync(testDir, { recursive: true }); } }, }); Deno.test( "[std/node/fs] Dir.close callback isn't called twice if error is thrown", async () => { const tempDir = await Deno.makeTempDir(); await assertCallbackErrorUncaught({ prelude: ` import { Dir } from "node:fs"; const dir = new Dir(${JSON.stringify(tempDir)}); `, invocation: "dir.close(", async cleanup() { await Deno.remove(tempDir); }, }); }, ); Deno.test( "[std/node/fs] Dir.read callback isn't called twice if error is thrown", async () => { const tempDir = await Deno.makeTempDir(); await assertCallbackErrorUncaught({ prelude: ` import { Dir } from "node:fs"; const dir = new Dir(${JSON.stringify(tempDir)}); `, invocation: "dir.read(", async cleanup() { await Deno.remove(tempDir); }, }); }, ); Deno.test({ name: "Dir.readSync throws ERR_DIR_CLOSED after closeSync", fn() { const testDir: string = Deno.makeTempDirSync(); try { const dir = new Dir(testDir); dir.closeSync(); try { dir.readSync(); fail("Expected ERR_DIR_CLOSED to be thrown"); } catch (e) { // deno-lint-ignore no-explicit-any assertEquals((e as any).code, "ERR_DIR_CLOSED"); } } finally { Deno.removeSync(testDir, { recursive: true }); } }, }); Deno.test({ name: "Dir.read rejects with ERR_DIR_CLOSED after close", async fn() { const testDir: string = Deno.makeTempDirSync(); try { const dir = new Dir(testDir); await dir.close(); try { await dir.read(); fail("Expected ERR_DIR_CLOSED to be thrown"); } catch (e) { // deno-lint-ignore no-explicit-any assertEquals((e as any).code, "ERR_DIR_CLOSED"); } } finally { Deno.removeSync(testDir, { recursive: true }); } }, }); Deno.test({ name: "Dir.readSync throws ERR_DIR_CLOSED after async close", async fn() { const testDir: string = Deno.makeTempDirSync(); try { const dir = new Dir(testDir); await dir.close(); try { dir.readSync(); fail("Expected ERR_DIR_CLOSED to be thrown"); } catch (e) { // deno-lint-ignore no-explicit-any assertEquals((e as any).code, "ERR_DIR_CLOSED"); } } finally { Deno.removeSync(testDir, { recursive: true }); } }, }); Deno.test({ name: "Dir.read callback receives ERR_DIR_CLOSED after close", async fn() { const testDir: string = Deno.makeTempDirSync(); try { const dir = new Dir(testDir); await dir.close(); await new Promise<void>((resolve, reject) => { // deno-lint-ignore no-explicit-any dir.read((err: any) => { try { assertEquals(err.code, "ERR_DIR_CLOSED"); resolve(); } catch (e) { reject(e); } }); }); } finally { Deno.removeSync(testDir, { recursive: true }); } }, });