mirror of
https://github.com/denoland/deno.git
synced 2024-11-22 04:51:22 +00:00
test(ext/node): port _fs tests from std/node (#18262)
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
This commit is contained in:
parent
3b1cb8af69
commit
bf149d047f
@ -11,7 +11,7 @@ Deno.test(
|
||||
async () => {
|
||||
const file = await Deno.makeTempFile();
|
||||
try {
|
||||
Deno.chmod(file, 0o600);
|
||||
await Deno.chmod(file, 0o600);
|
||||
await fs.promises.access(file, fs.constants.R_OK);
|
||||
await fs.promises.access(file, fs.constants.W_OK);
|
||||
await assertRejects(async () => {
|
||||
@ -43,7 +43,7 @@ Deno.test(
|
||||
() => {
|
||||
const file = Deno.makeTempFileSync();
|
||||
try {
|
||||
Deno.chmod(file, 0o600);
|
||||
Deno.chmodSync(file, 0o600);
|
||||
fs.accessSync(file, fs.constants.R_OK);
|
||||
fs.accessSync(file, fs.constants.W_OK);
|
||||
assertThrows(() => {
|
||||
|
259
cli/tests/unit_node/_fs/_fs_appendFile_test.ts
Normal file
259
cli/tests/unit_node/_fs/_fs_appendFile_test.ts
Normal file
@ -0,0 +1,259 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { appendFile, appendFileSync } from "node:fs";
|
||||
import { fromFileUrl } from "../../../../test_util/std/path/mod.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
|
||||
Deno.test({
|
||||
name: "No callback Fn results in Error",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
// @ts-expect-error Argument of type 'string' is not assignable to parameter of type 'NoParamCallback'
|
||||
appendFile("some/path", "some data", "utf8");
|
||||
},
|
||||
Error,
|
||||
"The \"cb\" argument must be of type function. Received type string ('utf8')",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Unsupported encoding results in error()",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
// @ts-expect-error Type '"made-up-encoding"' is not assignable to type
|
||||
appendFile("some/path", "some data", "made-up-encoding", () => {});
|
||||
},
|
||||
Error,
|
||||
"The argument 'made-up-encoding' is invalid encoding. Received 'encoding'",
|
||||
);
|
||||
assertThrows(
|
||||
() => {
|
||||
appendFile(
|
||||
"some/path",
|
||||
"some data",
|
||||
// @ts-expect-error Type '"made-up-encoding"' is not assignable to type
|
||||
{ encoding: "made-up-encoding" },
|
||||
() => {},
|
||||
);
|
||||
},
|
||||
Error,
|
||||
"The argument 'made-up-encoding' is invalid encoding. Received 'encoding'",
|
||||
);
|
||||
assertThrows(
|
||||
// @ts-expect-error Type '"made-up-encoding"' is not assignable to type
|
||||
() => appendFileSync("some/path", "some data", "made-up-encoding"),
|
||||
Error,
|
||||
"The argument 'made-up-encoding' is invalid encoding. Received 'encoding'",
|
||||
);
|
||||
assertThrows(
|
||||
() =>
|
||||
appendFileSync("some/path", "some data", {
|
||||
// @ts-expect-error Type '"made-up-encoding"' is not assignable to type
|
||||
encoding: "made-up-encoding",
|
||||
}),
|
||||
Error,
|
||||
"The argument 'made-up-encoding' is invalid encoding. Received 'encoding'",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Async: Data is written to passed in rid",
|
||||
async fn() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
const file: Deno.FsFile = await Deno.open(tempFile, {
|
||||
create: true,
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
appendFile(file.rid, "hello world", (err) => {
|
||||
if (err) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(async () => {
|
||||
const data = await Deno.readFile(tempFile);
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
}, () => {
|
||||
fail("No error expected");
|
||||
})
|
||||
.finally(async () => {
|
||||
Deno.close(file.rid);
|
||||
await Deno.remove(tempFile);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Async: Data is written to passed in file path",
|
||||
async fn() {
|
||||
const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
appendFile("_fs_appendFile_test_file.txt", "hello world", (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(async () => {
|
||||
assertEquals(Deno.resources(), openResourcesBeforeAppend);
|
||||
const data = await Deno.readFile("_fs_appendFile_test_file.txt");
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
}, (err) => {
|
||||
fail("No error was expected: " + err);
|
||||
})
|
||||
.finally(async () => {
|
||||
await Deno.remove("_fs_appendFile_test_file.txt");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Async: Data is written to passed in URL",
|
||||
async fn() {
|
||||
const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources();
|
||||
const fileURL = new URL("_fs_appendFile_test_file.txt", import.meta.url);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
appendFile(fileURL, "hello world", (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(async () => {
|
||||
assertEquals(Deno.resources(), openResourcesBeforeAppend);
|
||||
const data = await Deno.readFile(fromFileUrl(fileURL));
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
}, (err) => {
|
||||
fail("No error was expected: " + err);
|
||||
})
|
||||
.finally(async () => {
|
||||
await Deno.remove(fromFileUrl(fileURL));
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"Async: Callback is made with error if attempting to append data to an existing file with 'ax' flag",
|
||||
async fn() {
|
||||
const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources();
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
appendFile(tempFile, "hello world", { flag: "ax" }, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
fail("Expected error to be thrown");
|
||||
}, () => {
|
||||
assertEquals(Deno.resources(), openResourcesBeforeAppend);
|
||||
})
|
||||
.finally(async () => {
|
||||
await Deno.remove(tempFile);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Sync: Data is written to passed in rid",
|
||||
fn() {
|
||||
const tempFile: string = Deno.makeTempFileSync();
|
||||
const file: Deno.FsFile = Deno.openSync(tempFile, {
|
||||
create: true,
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
appendFileSync(file.rid, "hello world");
|
||||
Deno.close(file.rid);
|
||||
const data = Deno.readFileSync(tempFile);
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
Deno.removeSync(tempFile);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Sync: Data is written to passed in file path",
|
||||
fn() {
|
||||
const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources();
|
||||
appendFileSync("_fs_appendFile_test_file_sync.txt", "hello world");
|
||||
assertEquals(Deno.resources(), openResourcesBeforeAppend);
|
||||
const data = Deno.readFileSync("_fs_appendFile_test_file_sync.txt");
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
Deno.removeSync("_fs_appendFile_test_file_sync.txt");
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"Sync: error thrown if attempting to append data to an existing file with 'ax' flag",
|
||||
fn() {
|
||||
const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources();
|
||||
const tempFile: string = Deno.makeTempFileSync();
|
||||
assertThrows(
|
||||
() => appendFileSync(tempFile, "hello world", { flag: "ax" }),
|
||||
Error,
|
||||
"",
|
||||
);
|
||||
assertEquals(Deno.resources(), openResourcesBeforeAppend);
|
||||
Deno.removeSync(tempFile);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Sync: Data is written in Uint8Array to passed in file path",
|
||||
fn() {
|
||||
const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources();
|
||||
const testData = new TextEncoder().encode("hello world");
|
||||
appendFileSync("_fs_appendFile_test_file_sync.txt", testData);
|
||||
assertEquals(Deno.resources(), openResourcesBeforeAppend);
|
||||
const data = Deno.readFileSync("_fs_appendFile_test_file_sync.txt");
|
||||
assertEquals(data, testData);
|
||||
Deno.removeSync("_fs_appendFile_test_file_sync.txt");
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Async: Data is written in Uint8Array to passed in file path",
|
||||
async fn() {
|
||||
const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources();
|
||||
const testData = new TextEncoder().encode("hello world");
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
appendFile("_fs_appendFile_test_file.txt", testData, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(async () => {
|
||||
assertEquals(Deno.resources(), openResourcesBeforeAppend);
|
||||
const data = await Deno.readFile("_fs_appendFile_test_file.txt");
|
||||
assertEquals(data, testData);
|
||||
}, (err) => {
|
||||
fail("No error was expected: " + err);
|
||||
})
|
||||
.finally(async () => {
|
||||
await Deno.remove("_fs_appendFile_test_file.txt");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] appendFile callback isn't called twice if error is thrown", async () => {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { appendFile } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `appendFile(${JSON.stringify(tempFile)}, "hello world", `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempFile);
|
||||
},
|
||||
});
|
||||
});
|
121
cli/tests/unit_node/_fs/_fs_chmod_test.ts
Normal file
121
cli/tests/unit_node/_fs/_fs_chmod_test.ts
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assert,
|
||||
assertRejects,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { chmod, chmodSync } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: Permissions are changed (non-Windows)",
|
||||
ignore: Deno.build.os === "windows",
|
||||
async fn() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
const originalFileMode: number | null = (await Deno.lstat(tempFile)).mode;
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
chmod(tempFile, 0o777, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
const newFileMode: number | null = Deno.lstatSync(tempFile).mode;
|
||||
assert(newFileMode && originalFileMode);
|
||||
assert(newFileMode === 33279 && newFileMode > originalFileMode);
|
||||
}, (error) => {
|
||||
fail(error);
|
||||
})
|
||||
.finally(() => {
|
||||
Deno.removeSync(tempFile);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: don't throw NotSupportedError (Windows)",
|
||||
ignore: Deno.build.os !== "windows",
|
||||
async fn() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
chmod(tempFile, 0o777, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
}).finally(() => {
|
||||
Deno.removeSync(tempFile);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: don't swallow NotFoundError (Windows)",
|
||||
ignore: Deno.build.os !== "windows",
|
||||
async fn() {
|
||||
await assertRejects(async () => {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
chmod("./__non_existent_file__", 0o777, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: Permissions are changed (non-Windows)",
|
||||
ignore: Deno.build.os === "windows",
|
||||
fn() {
|
||||
const tempFile: string = Deno.makeTempFileSync();
|
||||
try {
|
||||
const originalFileMode: number | null = Deno.lstatSync(tempFile).mode;
|
||||
chmodSync(tempFile, "777");
|
||||
|
||||
const newFileMode: number | null = Deno.lstatSync(tempFile).mode;
|
||||
assert(newFileMode && originalFileMode);
|
||||
assert(newFileMode === 33279 && newFileMode > originalFileMode);
|
||||
} finally {
|
||||
Deno.removeSync(tempFile);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: don't throw NotSupportedError (Windows)",
|
||||
ignore: Deno.build.os !== "windows",
|
||||
fn() {
|
||||
const tempFile: string = Deno.makeTempFileSync();
|
||||
try {
|
||||
chmodSync(tempFile, "777");
|
||||
} finally {
|
||||
Deno.removeSync(tempFile);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: don't swallow NotFoundError (Windows)",
|
||||
ignore: Deno.build.os !== "windows",
|
||||
fn() {
|
||||
assertThrows(() => {
|
||||
chmodSync("./__non_existent_file__", "777");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[std/node/fs] chmod callback isn't called twice if error is thrown",
|
||||
async fn() {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { chmod } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `chmod(${JSON.stringify(tempFile)}, 0o777, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempFile);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
72
cli/tests/unit_node/_fs/_fs_chown_test.ts
Normal file
72
cli/tests/unit_node/_fs/_fs_chown_test.ts
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { chown, chownSync } from "node:fs";
|
||||
|
||||
// chown is difficult to test. Best we can do is set the existing user id/group
|
||||
// id again
|
||||
const ignore = Deno.build.os === "windows";
|
||||
|
||||
Deno.test({
|
||||
ignore,
|
||||
name: "ASYNC: setting existing uid/gid works as expected (non-Windows)",
|
||||
async fn() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
const originalUserId: number | null = (await Deno.lstat(tempFile)).uid;
|
||||
const originalGroupId: number | null = (await Deno.lstat(tempFile)).gid;
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
chown(tempFile, originalUserId!, originalGroupId!, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
const newUserId: number | null = Deno.lstatSync(tempFile).uid;
|
||||
const newGroupId: number | null = Deno.lstatSync(tempFile).gid;
|
||||
assertEquals(newUserId, originalUserId);
|
||||
assertEquals(newGroupId, originalGroupId);
|
||||
}, () => {
|
||||
fail();
|
||||
})
|
||||
.finally(() => {
|
||||
Deno.removeSync(tempFile);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
ignore,
|
||||
name: "SYNC: setting existing uid/gid works as expected (non-Windows)",
|
||||
fn() {
|
||||
const tempFile: string = Deno.makeTempFileSync();
|
||||
const originalUserId: number | null = Deno.lstatSync(tempFile).uid;
|
||||
const originalGroupId: number | null = Deno.lstatSync(tempFile).gid;
|
||||
chownSync(tempFile, originalUserId!, originalGroupId!);
|
||||
|
||||
const newUserId: number | null = Deno.lstatSync(tempFile).uid;
|
||||
const newGroupId: number | null = Deno.lstatSync(tempFile).gid;
|
||||
assertEquals(newUserId, originalUserId);
|
||||
assertEquals(newGroupId, originalGroupId);
|
||||
Deno.removeSync(tempFile);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[std/node/fs] chown callback isn't called twice if error is thrown",
|
||||
ignore: Deno.build.os === "windows",
|
||||
async fn() {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const { uid, gid } = await Deno.lstat(tempFile);
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { chown } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `chown(${JSON.stringify(tempFile)}, ${uid}, ${gid}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempFile);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
97
cli/tests/unit_node/_fs/_fs_close_test.ts
Normal file
97
cli/tests/unit_node/_fs/_fs_close_test.ts
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assert,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { close, closeSync } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: File is closed",
|
||||
async fn() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
const file: Deno.FsFile = await Deno.open(tempFile);
|
||||
|
||||
assert(Deno.resources()[file.rid]);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
close(file.rid, (err) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
assert(!Deno.resources()[file.rid]);
|
||||
}, () => {
|
||||
fail("No error expected");
|
||||
})
|
||||
.finally(async () => {
|
||||
await Deno.remove(tempFile);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: Invalid fd",
|
||||
fn() {
|
||||
assertThrows(() => {
|
||||
close(-1, (_err) => {});
|
||||
}, RangeError);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "close callback should be asynchronous",
|
||||
async fn() {
|
||||
const tempFile: string = Deno.makeTempFileSync();
|
||||
const file: Deno.FsFile = Deno.openSync(tempFile);
|
||||
|
||||
let foo: string;
|
||||
const promise = new Promise<void>((resolve) => {
|
||||
close(file.rid, () => {
|
||||
assert(foo === "bar");
|
||||
resolve();
|
||||
});
|
||||
foo = "bar";
|
||||
});
|
||||
|
||||
await promise;
|
||||
Deno.removeSync(tempFile);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: File is closed",
|
||||
fn() {
|
||||
const tempFile: string = Deno.makeTempFileSync();
|
||||
const file: Deno.FsFile = Deno.openSync(tempFile);
|
||||
|
||||
assert(Deno.resources()[file.rid]);
|
||||
closeSync(file.rid);
|
||||
assert(!Deno.resources()[file.rid]);
|
||||
Deno.removeSync(tempFile);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: Invalid fd",
|
||||
fn() {
|
||||
assertThrows(() => closeSync(-1));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] close callback isn't called twice if error is thrown", async () => {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `
|
||||
import { close } from ${JSON.stringify(importUrl)};
|
||||
|
||||
const file = await Deno.open(${JSON.stringify(tempFile)});
|
||||
`,
|
||||
invocation: "close(file.rid, ",
|
||||
async cleanup() {
|
||||
await Deno.remove(tempFile);
|
||||
},
|
||||
});
|
||||
});
|
52
cli/tests/unit_node/_fs/_fs_copy_test.ts
Normal file
52
cli/tests/unit_node/_fs/_fs_copy_test.ts
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import * as path from "../../../../test_util/std/path/mod.ts";
|
||||
import { assert } from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { copyFile, copyFileSync, existsSync } from "node:fs";
|
||||
|
||||
const destFile = "./destination.txt";
|
||||
|
||||
Deno.test({
|
||||
name: "[std/node/fs] copy file",
|
||||
fn: async () => {
|
||||
const sourceFile = Deno.makeTempFileSync();
|
||||
const err = await new Promise((resolve) => {
|
||||
copyFile(sourceFile, destFile, (err?: Error | null) => resolve(err));
|
||||
});
|
||||
assert(!err);
|
||||
assert(existsSync(destFile));
|
||||
Deno.removeSync(sourceFile);
|
||||
Deno.removeSync(destFile);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[std/node/fs] copy file sync",
|
||||
fn: () => {
|
||||
const sourceFile = Deno.makeTempFileSync();
|
||||
copyFileSync(sourceFile, destFile);
|
||||
assert(existsSync(destFile));
|
||||
Deno.removeSync(sourceFile);
|
||||
Deno.removeSync(destFile);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] copyFile callback isn't called twice if error is thrown", async () => {
|
||||
// The correct behaviour is not to catch any errors thrown,
|
||||
// but that means there'll be an uncaught error and the test will fail.
|
||||
// So the only way to test this is to spawn a subprocess, and succeed if it has a non-zero exit code.
|
||||
// (assertRejects won't work because there's no way to catch the error.)
|
||||
const tempDir = await Deno.makeTempDir();
|
||||
const tempFile1 = path.join(tempDir, "file1.txt");
|
||||
const tempFile2 = path.join(tempDir, "file2.txt");
|
||||
await Deno.writeTextFile(tempFile1, "hello world");
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { copyFile } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `copyFile(${JSON.stringify(tempFile1)},
|
||||
${JSON.stringify(tempFile2)}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempDir, { recursive: true });
|
||||
},
|
||||
});
|
||||
});
|
65
cli/tests/unit_node/_fs/_fs_exists_test.ts
Normal file
65
cli/tests/unit_node/_fs/_fs_exists_test.ts
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
assertStringIncludes,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { exists, existsSync } from "node:fs";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
Deno.test("[std/node/fs] exists", async function () {
|
||||
const availableFile = await new Promise((resolve) => {
|
||||
const tmpFilePath = Deno.makeTempFileSync();
|
||||
exists(tmpFilePath, (exists: boolean) => {
|
||||
Deno.removeSync(tmpFilePath);
|
||||
resolve(exists);
|
||||
});
|
||||
});
|
||||
const notAvailableFile = await new Promise((resolve) => {
|
||||
exists("./notAvailable.txt", (exists: boolean) => resolve(exists));
|
||||
});
|
||||
assertEquals(availableFile, true);
|
||||
assertEquals(notAvailableFile, false);
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] existsSync", function () {
|
||||
const tmpFilePath = Deno.makeTempFileSync();
|
||||
assertEquals(existsSync(tmpFilePath), true);
|
||||
Deno.removeSync(tmpFilePath);
|
||||
assertEquals(existsSync("./notAvailable.txt"), false);
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] promisify(exists)", async () => {
|
||||
const tmpFilePath = await Deno.makeTempFile();
|
||||
try {
|
||||
const existsPromisified = promisify(exists);
|
||||
assert(await existsPromisified(tmpFilePath));
|
||||
assert(!await existsPromisified("./notAvailable.txt"));
|
||||
} finally {
|
||||
await Deno.remove(tmpFilePath);
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] exists callback isn't called twice if error is thrown", async () => {
|
||||
// This doesn't use `assertCallbackErrorUncaught()` because `exists()` doesn't return a standard node callback, which is what it expects.
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
const command = new Deno.Command(Deno.execPath(), {
|
||||
args: [
|
||||
"eval",
|
||||
"--no-check",
|
||||
`
|
||||
import { exists } from ${JSON.stringify(importUrl)};
|
||||
|
||||
exists(${JSON.stringify(tempFile)}, (exists) => {
|
||||
// If the bug is present and the callback is called again with false (meaning an error occurred),
|
||||
// don't throw another error, so if the subprocess fails we know it had the correct behaviour.
|
||||
if (exists) throw new Error("success");
|
||||
});`,
|
||||
],
|
||||
});
|
||||
const { success, stderr } = await command.output();
|
||||
await Deno.remove(tempFile);
|
||||
assert(!success);
|
||||
assertStringIncludes(new TextDecoder().decode(stderr), "Error: success");
|
||||
});
|
63
cli/tests/unit_node/_fs/_fs_fdatasync_test.ts
Normal file
63
cli/tests/unit_node/_fs/_fs_fdatasync_test.ts
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { fdatasync, fdatasyncSync } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"ASYNC: flush any pending data operations of the given file stream to disk",
|
||||
async fn() {
|
||||
const file: string = await Deno.makeTempFile();
|
||||
const { rid } = await Deno.open(file, {
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
});
|
||||
const data = new Uint8Array(64);
|
||||
await Deno.write(rid, data);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
fdatasync(rid, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
async () => {
|
||||
assertEquals(await Deno.readFile(file), data);
|
||||
},
|
||||
() => {
|
||||
fail("No error expected");
|
||||
},
|
||||
)
|
||||
.finally(async () => {
|
||||
Deno.close(rid);
|
||||
await Deno.remove(file);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"SYNC: flush any pending data operations of the given file stream to disk.",
|
||||
fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
const { rid } = Deno.openSync(file, {
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
});
|
||||
const data = new Uint8Array(64);
|
||||
Deno.writeSync(rid, data);
|
||||
|
||||
try {
|
||||
fdatasyncSync(rid);
|
||||
assertEquals(Deno.readFileSync(file), data);
|
||||
} finally {
|
||||
Deno.close(rid);
|
||||
Deno.removeSync(file);
|
||||
}
|
||||
},
|
||||
});
|
83
cli/tests/unit_node/_fs/_fs_fstat_test.ts
Normal file
83
cli/tests/unit_node/_fs/_fs_fstat_test.ts
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { fstat, fstatSync } from "node:fs";
|
||||
import { fail } from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertStats, assertStatsBigInt } from "./_fs_stat_test.ts";
|
||||
import type { BigIntStats, Stats } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: get a file Stats",
|
||||
async fn() {
|
||||
const file = await Deno.makeTempFile();
|
||||
const { rid } = await Deno.open(file);
|
||||
|
||||
await new Promise<Stats>((resolve, reject) => {
|
||||
fstat(rid, (err: Error | null, stat: Stats) => {
|
||||
if (err) reject(err);
|
||||
resolve(stat);
|
||||
});
|
||||
})
|
||||
.then(
|
||||
(stat) => {
|
||||
assertStats(stat, Deno.fstatSync(rid));
|
||||
},
|
||||
() => fail(),
|
||||
)
|
||||
.finally(() => {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: get a file BigInt Stats",
|
||||
async fn() {
|
||||
const file = await Deno.makeTempFile();
|
||||
const { rid } = await Deno.open(file);
|
||||
|
||||
await new Promise<BigIntStats>((resolve, reject) => {
|
||||
fstat(rid, { bigint: true }, (err: Error | null, stat: BigIntStats) => {
|
||||
if (err) reject(err);
|
||||
resolve(stat);
|
||||
});
|
||||
})
|
||||
.then(
|
||||
(stat) => assertStatsBigInt(stat, Deno.fstatSync(rid)),
|
||||
() => fail(),
|
||||
)
|
||||
.finally(() => {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: get a file Stats",
|
||||
fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
const { rid } = Deno.openSync(file);
|
||||
|
||||
try {
|
||||
assertStats(fstatSync(rid), Deno.fstatSync(rid));
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: get a file BigInt Stats",
|
||||
fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
const { rid } = Deno.openSync(file);
|
||||
|
||||
try {
|
||||
assertStatsBigInt(fstatSync(rid, { bigint: true }), Deno.fstatSync(rid));
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
}
|
||||
},
|
||||
});
|
61
cli/tests/unit_node/_fs/_fs_fsync_test.ts
Normal file
61
cli/tests/unit_node/_fs/_fs_fsync_test.ts
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { fsync, fsyncSync } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: flush any pending data of the given file stream to disk",
|
||||
async fn() {
|
||||
const file: string = await Deno.makeTempFile();
|
||||
const { rid } = await Deno.open(file, {
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
});
|
||||
const size = 64;
|
||||
await Deno.ftruncate(rid, size);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
fsync(rid, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
async () => {
|
||||
assertEquals((await Deno.stat(file)).size, size);
|
||||
},
|
||||
() => {
|
||||
fail("No error expected");
|
||||
},
|
||||
)
|
||||
.finally(async () => {
|
||||
await Deno.remove(file);
|
||||
Deno.close(rid);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: flush any pending data the given file stream to disk",
|
||||
fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
const { rid } = Deno.openSync(file, {
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
});
|
||||
const size = 64;
|
||||
Deno.ftruncateSync(rid, size);
|
||||
|
||||
try {
|
||||
fsyncSync(rid);
|
||||
assertEquals(Deno.statSync(file).size, size);
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
}
|
||||
},
|
||||
});
|
131
cli/tests/unit_node/_fs/_fs_ftruncate_test.ts
Normal file
131
cli/tests/unit_node/_fs/_fs_ftruncate_test.ts
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { ftruncate, ftruncateSync } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: no callback function results in Error",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
// @ts-expect-error Argument of type 'number' is not assignable to parameter of type 'NoParamCallback'
|
||||
ftruncate(123, 0);
|
||||
},
|
||||
Error,
|
||||
"No callback function supplied",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: truncate entire file contents",
|
||||
async fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
await Deno.writeFile(file, new TextEncoder().encode("hello world"));
|
||||
const { rid } = await Deno.open(file, {
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
ftruncate(rid, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.size, 0);
|
||||
},
|
||||
() => {
|
||||
fail("No error expected");
|
||||
},
|
||||
)
|
||||
.finally(() => {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: truncate file to a size of precisely len bytes",
|
||||
async fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
await Deno.writeFile(file, new TextEncoder().encode("hello world"));
|
||||
const { rid } = await Deno.open(file, {
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
ftruncate(rid, 3, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.size, 3);
|
||||
},
|
||||
() => {
|
||||
fail("No error expected");
|
||||
},
|
||||
)
|
||||
.finally(() => {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: truncate entire file contents",
|
||||
fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
Deno.writeFileSync(file, new TextEncoder().encode("hello world"));
|
||||
const { rid } = Deno.openSync(file, {
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
});
|
||||
|
||||
try {
|
||||
ftruncateSync(rid);
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.size, 0);
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: truncate file to a size of precisely len bytes",
|
||||
fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
Deno.writeFileSync(file, new TextEncoder().encode("hello world"));
|
||||
const { rid } = Deno.openSync(file, {
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
});
|
||||
|
||||
try {
|
||||
ftruncateSync(rid, 3);
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.size, 3);
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
}
|
||||
},
|
||||
});
|
112
cli/tests/unit_node/_fs/_fs_futimes_test.ts
Normal file
112
cli/tests/unit_node/_fs/_fs_futimes_test.ts
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { futimes, futimesSync } from "node:fs";
|
||||
|
||||
const randomDate = new Date(Date.now() + 1000);
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"ASYNC: change the file system timestamps of the object referenced by path",
|
||||
async fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
const { rid } = await Deno.open(file, { create: true, write: true });
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
futimes(rid, randomDate, randomDate, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.mtime, randomDate);
|
||||
assertEquals(fileInfo.atime, randomDate);
|
||||
},
|
||||
() => {
|
||||
fail("No error expected");
|
||||
},
|
||||
)
|
||||
.finally(() => {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: should throw error if atime is infinity",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
futimes(123, Infinity, 0, (_err: Error | null) => {});
|
||||
},
|
||||
Error,
|
||||
"invalid atime, must not be infinity or NaN",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: should throw error if atime is NaN",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
futimes(123, "some string", 0, (_err: Error | null) => {});
|
||||
},
|
||||
Error,
|
||||
"invalid atime, must not be infinity or NaN",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"SYNC: change the file system timestamps of the object referenced by path",
|
||||
fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
const { rid } = Deno.openSync(file, { create: true, write: true });
|
||||
|
||||
try {
|
||||
futimesSync(rid, randomDate, randomDate);
|
||||
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
|
||||
assertEquals(fileInfo.mtime, randomDate);
|
||||
assertEquals(fileInfo.atime, randomDate);
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
Deno.close(rid);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: should throw error if atime is NaN",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
futimesSync(123, "some string", 0);
|
||||
},
|
||||
Error,
|
||||
"invalid atime, must not be infinity or NaN",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: should throw error if atime is Infinity",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
futimesSync(123, Infinity, 0);
|
||||
},
|
||||
Error,
|
||||
"invalid atime, must not be infinity or NaN",
|
||||
);
|
||||
},
|
||||
});
|
81
cli/tests/unit_node/_fs/_fs_link_test.ts
Normal file
81
cli/tests/unit_node/_fs/_fs_link_test.ts
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import * as path from "../../../../test_util/std/path/mod.ts";
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { link, linkSync } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: hard linking files works as expected",
|
||||
async fn() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
const linkedFile: string = tempFile + ".link";
|
||||
await new Promise<void>((res, rej) => {
|
||||
link(tempFile, linkedFile, (err) => {
|
||||
if (err) rej(err);
|
||||
else res();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
assertEquals(Deno.statSync(tempFile), Deno.statSync(linkedFile));
|
||||
}, () => {
|
||||
fail("Expected to succeed");
|
||||
})
|
||||
.finally(() => {
|
||||
Deno.removeSync(tempFile);
|
||||
Deno.removeSync(linkedFile);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: hard linking files passes error to callback",
|
||||
async fn() {
|
||||
let failed = false;
|
||||
await new Promise<void>((res, rej) => {
|
||||
link("no-such-file", "no-such-file", (err) => {
|
||||
if (err) rej(err);
|
||||
else res();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
fail("Expected to succeed");
|
||||
}, (err) => {
|
||||
assert(err);
|
||||
failed = true;
|
||||
});
|
||||
assert(failed);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: hard linking files works as expected",
|
||||
fn() {
|
||||
const tempFile: string = Deno.makeTempFileSync();
|
||||
const linkedFile: string = tempFile + ".link";
|
||||
linkSync(tempFile, linkedFile);
|
||||
|
||||
assertEquals(Deno.statSync(tempFile), Deno.statSync(linkedFile));
|
||||
Deno.removeSync(tempFile);
|
||||
Deno.removeSync(linkedFile);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] link callback isn't called twice if error is thrown", async () => {
|
||||
const tempDir = await Deno.makeTempDir();
|
||||
const tempFile = path.join(tempDir, "file.txt");
|
||||
const linkFile = path.join(tempDir, "link.txt");
|
||||
await Deno.writeTextFile(tempFile, "hello world");
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { link } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `link(${JSON.stringify(tempFile)},
|
||||
${JSON.stringify(linkFile)}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempDir, { recursive: true });
|
||||
},
|
||||
});
|
||||
});
|
71
cli/tests/unit_node/_fs/_fs_lstat_test.ts
Normal file
71
cli/tests/unit_node/_fs/_fs_lstat_test.ts
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { lstat, lstatSync } from "node:fs";
|
||||
import { fail } from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { assertStats, assertStatsBigInt } from "./_fs_stat_test.ts";
|
||||
import type { BigIntStats, Stats } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: get a file Stats (lstat)",
|
||||
async fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
await new Promise<Stats>((resolve, reject) => {
|
||||
lstat(file, (err, stat) => {
|
||||
if (err) reject(err);
|
||||
resolve(stat);
|
||||
});
|
||||
})
|
||||
.then((stat) => {
|
||||
assertStats(stat, Deno.lstatSync(file));
|
||||
}, () => fail())
|
||||
.finally(() => {
|
||||
Deno.removeSync(file);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: get a file Stats (lstat)",
|
||||
fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
assertStats(lstatSync(file), Deno.lstatSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: get a file BigInt Stats (lstat)",
|
||||
async fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
await new Promise<BigIntStats>((resolve, reject) => {
|
||||
lstat(file, { bigint: true }, (err, stat) => {
|
||||
if (err) reject(err);
|
||||
resolve(stat);
|
||||
});
|
||||
})
|
||||
.then(
|
||||
(stat) => assertStatsBigInt(stat, Deno.lstatSync(file)),
|
||||
() => fail(),
|
||||
)
|
||||
.finally(() => Deno.removeSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: BigInt Stats (lstat)",
|
||||
fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
assertStatsBigInt(lstatSync(file, { bigint: true }), Deno.lstatSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] lstat callback isn't called twice if error is thrown", async () => {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { lstat } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `lstat(${JSON.stringify(tempFile)}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempFile);
|
||||
},
|
||||
});
|
||||
});
|
43
cli/tests/unit_node/_fs/_fs_mkdir_test.ts
Normal file
43
cli/tests/unit_node/_fs/_fs_mkdir_test.ts
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import * as path from "../../../../test_util/std/path/mod.ts";
|
||||
import { assert } from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { existsSync, mkdir, mkdirSync } from "node:fs";
|
||||
|
||||
const tmpDir = "./tmpdir";
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdir",
|
||||
fn: async () => {
|
||||
const result = await new Promise((resolve) => {
|
||||
mkdir(tmpDir, (err) => {
|
||||
err && resolve(false);
|
||||
resolve(existsSync(tmpDir));
|
||||
Deno.removeSync(tmpDir);
|
||||
});
|
||||
});
|
||||
assert(result);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdirSync",
|
||||
fn: () => {
|
||||
mkdirSync(tmpDir);
|
||||
assert(existsSync(tmpDir));
|
||||
Deno.removeSync(tmpDir);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] mkdir callback isn't called twice if error is thrown", async () => {
|
||||
const tempDir = await Deno.makeTempDir();
|
||||
const subdir = path.join(tempDir, "subdir");
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { mkdir } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `mkdir(${JSON.stringify(subdir)}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempDir, { recursive: true });
|
||||
},
|
||||
});
|
||||
});
|
86
cli/tests/unit_node/_fs/_fs_mkdtemp_test.ts
Normal file
86
cli/tests/unit_node/_fs/_fs_mkdtemp_test.ts
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assert,
|
||||
assertRejects,
|
||||
assertThrows,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { EncodingOption, existsSync, mkdtemp, mkdtempSync } from "node:fs";
|
||||
import { env } from "node:process";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
const prefix = Deno.build.os === "windows"
|
||||
? env.TEMP + "\\"
|
||||
: (env.TMPDIR || "/tmp") + "/";
|
||||
const doesNotExists = "/does/not/exists/";
|
||||
const options: EncodingOption = { encoding: "ascii" };
|
||||
const badOptions = { encoding: "bogus" };
|
||||
|
||||
const mkdtempP = promisify(mkdtemp);
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdtemp",
|
||||
fn: async () => {
|
||||
const directory = await mkdtempP(prefix);
|
||||
assert(existsSync(directory));
|
||||
Deno.removeSync(directory);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdtemp (does not exists)",
|
||||
fn: async () => {
|
||||
await assertRejects(() => mkdtempP(doesNotExists));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdtemp (with options)",
|
||||
fn: async () => {
|
||||
const directory = await mkdtempP(prefix, options);
|
||||
assert(existsSync(directory));
|
||||
Deno.removeSync(directory);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdtemp (with bad options)",
|
||||
fn: async () => {
|
||||
// @ts-expect-error No overload matches this call
|
||||
await assertRejects(() => mkdtempP(prefix, badOptions));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdtempSync",
|
||||
fn: () => {
|
||||
const directory = mkdtempSync(prefix);
|
||||
const dirExists = existsSync(directory);
|
||||
Deno.removeSync(directory);
|
||||
assert(dirExists);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdtempSync (does not exists)",
|
||||
fn: () => {
|
||||
assertThrows(() => mkdtempSync(doesNotExists));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdtempSync (with options)",
|
||||
fn: () => {
|
||||
const directory = mkdtempSync(prefix, options);
|
||||
const dirExists = existsSync(directory);
|
||||
Deno.removeSync(directory);
|
||||
assert(dirExists);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "[node/fs] mkdtempSync (with bad options)",
|
||||
fn: () => {
|
||||
// @ts-expect-error No overload matches this call
|
||||
assertThrows(() => mkdtempSync(prefix, badOptions));
|
||||
},
|
||||
});
|
146
cli/tests/unit_node/_fs/_fs_opendir_test.ts
Normal file
146
cli/tests/unit_node/_fs/_fs_opendir_test.ts
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
assertFalse,
|
||||
assertInstanceOf,
|
||||
assertThrows,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { opendir, opendirSync } from "node:fs";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
|
||||
Deno.test("[node/fs] opendir()", async (t) => {
|
||||
const path = await Deno.makeTempDir();
|
||||
const file = await Deno.makeTempFile();
|
||||
|
||||
await t.step(
|
||||
"fails if encoding is invalid",
|
||||
() =>
|
||||
opendir(
|
||||
path,
|
||||
// @ts-expect-error Type '"invalid-encoding"' is not assignable to type 'BufferEncoding | undefined'
|
||||
{ encoding: "invalid-encoding" },
|
||||
(err) => assertInstanceOf(err, TypeError),
|
||||
),
|
||||
);
|
||||
|
||||
await t.step(
|
||||
"fails if bufferSize is invalid",
|
||||
() =>
|
||||
opendir(
|
||||
path,
|
||||
{ bufferSize: -1 },
|
||||
(err) => assertInstanceOf(err, RangeError),
|
||||
),
|
||||
);
|
||||
|
||||
await t.step(
|
||||
"fails if directory does not exist",
|
||||
() =>
|
||||
opendir(
|
||||
"directory-that-does-not-exist",
|
||||
(err) => assertInstanceOf(err, Error),
|
||||
),
|
||||
);
|
||||
|
||||
await t.step(
|
||||
"fails if not a directory",
|
||||
() =>
|
||||
opendir(
|
||||
file,
|
||||
(err) => assertInstanceOf(err, Error),
|
||||
),
|
||||
);
|
||||
|
||||
await t.step(
|
||||
"passes if path is a string",
|
||||
() =>
|
||||
opendir(
|
||||
path,
|
||||
(err, dir) => {
|
||||
assertEquals(err, null);
|
||||
assert(dir);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
await t.step(
|
||||
"passes if path is a Buffer",
|
||||
() =>
|
||||
opendir(
|
||||
Buffer.from(path),
|
||||
(err, dir) => {
|
||||
assertFalse(err);
|
||||
assert(dir);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
await t.step(
|
||||
"passes if path is a URL",
|
||||
() =>
|
||||
opendir(
|
||||
new URL(`file://` + path),
|
||||
(err, dir) => {
|
||||
assertFalse(err);
|
||||
assert(dir);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
await t.step("passes if callback isn't called twice", async () => {
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { opendir } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `opendir(${JSON.stringify(path)}, `,
|
||||
});
|
||||
});
|
||||
|
||||
await Deno.remove(path);
|
||||
await Deno.remove(file);
|
||||
});
|
||||
|
||||
Deno.test("[node/fs] opendirSync()", async (t) => {
|
||||
const path = await Deno.makeTempDir();
|
||||
const file = await Deno.makeTempFile();
|
||||
|
||||
await t.step("fails if encoding is invalid", () => {
|
||||
assertThrows(
|
||||
// @ts-expect-error Type '"invalid-encoding"' is not assignable to type 'BufferEncoding | undefined'
|
||||
() => opendirSync(path, { encoding: "invalid-encoding" }),
|
||||
TypeError,
|
||||
);
|
||||
});
|
||||
|
||||
await t.step("fails if bufferSize is invalid", () => {
|
||||
assertThrows(
|
||||
() => opendirSync(path, { bufferSize: -1 }),
|
||||
RangeError,
|
||||
);
|
||||
});
|
||||
|
||||
await t.step("fails if directory does not exist", () => {
|
||||
assertThrows(() => opendirSync("directory-that-does-not-exist"));
|
||||
});
|
||||
|
||||
await t.step("fails if not a directory", () => {
|
||||
assertThrows(() => opendirSync(file));
|
||||
});
|
||||
|
||||
await t.step("passes if path is a string", () => {
|
||||
assert(opendirSync(path));
|
||||
});
|
||||
|
||||
await t.step("passes if path is a Buffer", () => {
|
||||
assert(opendirSync(Buffer.from(path)));
|
||||
});
|
||||
|
||||
await t.step("passes if path is a URL", () => {
|
||||
assert(opendirSync(new URL(`file://` + path)));
|
||||
});
|
||||
|
||||
await Deno.remove(path);
|
||||
await Deno.remove(file);
|
||||
});
|
121
cli/tests/unit_node/_fs/_fs_readFile_test.ts
Normal file
121
cli/tests/unit_node/_fs/_fs_readFile_test.ts
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { readFile, readFileSync } from "node:fs";
|
||||
import * as path from "../../../../test_util/std/path/mod.ts";
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
|
||||
const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
|
||||
const testData = path.resolve(moduleDir, "testdata", "hello.txt");
|
||||
|
||||
Deno.test("readFileSuccess", async function () {
|
||||
const data = await new Promise((res, rej) => {
|
||||
readFile(testData, (err, data) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
}
|
||||
res(data);
|
||||
});
|
||||
});
|
||||
|
||||
assert(data instanceof Uint8Array);
|
||||
assertEquals(new TextDecoder().decode(data as Uint8Array), "hello world");
|
||||
});
|
||||
|
||||
Deno.test("readFileEncodeUtf8Success", async function () {
|
||||
const data = await new Promise((res, rej) => {
|
||||
readFile(testData, { encoding: "utf8" }, (err, data) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
}
|
||||
res(data);
|
||||
});
|
||||
});
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, "hello world");
|
||||
});
|
||||
|
||||
Deno.test("readFileEncodeHexSuccess", async function () {
|
||||
const data = await new Promise((res, rej) => {
|
||||
readFile(testData, { encoding: "hex" }, (err, data) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
}
|
||||
res(data);
|
||||
});
|
||||
});
|
||||
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, "68656c6c6f20776f726c64");
|
||||
});
|
||||
|
||||
Deno.test("readFileEncodeBase64Success", async function () {
|
||||
const data = await new Promise((res, rej) => {
|
||||
readFile(testData, { encoding: "base64" }, (err, data) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
}
|
||||
res(data);
|
||||
});
|
||||
});
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, "aGVsbG8gd29ybGQ=");
|
||||
});
|
||||
|
||||
Deno.test("readFileEncodingAsString", async function () {
|
||||
const data = await new Promise((res, rej) => {
|
||||
readFile(testData, "utf8", (err, data) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
}
|
||||
res(data);
|
||||
});
|
||||
});
|
||||
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, "hello world");
|
||||
});
|
||||
|
||||
Deno.test("readFileSyncSuccess", function () {
|
||||
const data = readFileSync(testData);
|
||||
assert(data instanceof Uint8Array);
|
||||
assertEquals(new TextDecoder().decode(data as Uint8Array), "hello world");
|
||||
});
|
||||
|
||||
Deno.test("readFileEncodeUtf8Success", function () {
|
||||
const data = readFileSync(testData, { encoding: "utf8" });
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, "hello world");
|
||||
});
|
||||
|
||||
Deno.test("readFileEncodeHexSuccess", function () {
|
||||
const data = readFileSync(testData, { encoding: "hex" });
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, "68656c6c6f20776f726c64");
|
||||
});
|
||||
|
||||
Deno.test("readFileEncodeBase64Success", function () {
|
||||
const data = readFileSync(testData, { encoding: "base64" });
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, "aGVsbG8gd29ybGQ=");
|
||||
});
|
||||
|
||||
Deno.test("readFileEncodeAsString", function () {
|
||||
const data = readFileSync(testData, "utf8");
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, "hello world");
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] readFile callback isn't called twice if error is thrown", async () => {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { readFile } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `readFile(${JSON.stringify(tempFile)}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempFile);
|
||||
},
|
||||
});
|
||||
});
|
96
cli/tests/unit_node/_fs/_fs_readdir_test.ts
Normal file
96
cli/tests/unit_node/_fs/_fs_readdir_test.ts
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
assertNotEquals,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { readdir, readdirSync } from "node:fs";
|
||||
import { join } from "../../../../test_util/std/path/mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: reading empty directory",
|
||||
async fn() {
|
||||
const dir = Deno.makeTempDirSync();
|
||||
await new Promise<string[]>((resolve, reject) => {
|
||||
readdir(dir, (err, files) => {
|
||||
if (err) reject(err);
|
||||
resolve(files);
|
||||
});
|
||||
})
|
||||
.then((files) => assertEquals(files, []), () => fail())
|
||||
.finally(() => Deno.removeSync(dir));
|
||||
},
|
||||
});
|
||||
|
||||
function assertEqualsArrayAnyOrder<T>(actual: T[], expected: T[]) {
|
||||
assertEquals(actual.length, expected.length);
|
||||
for (const item of expected) {
|
||||
const index = actual.indexOf(item);
|
||||
assertNotEquals(index, -1);
|
||||
expected = expected.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: reading non-empty directory",
|
||||
async fn() {
|
||||
const dir = Deno.makeTempDirSync();
|
||||
Deno.writeTextFileSync(join(dir, "file1.txt"), "hi");
|
||||
Deno.writeTextFileSync(join(dir, "file2.txt"), "hi");
|
||||
Deno.mkdirSync(join(dir, "some_dir"));
|
||||
await new Promise<string[]>((resolve, reject) => {
|
||||
readdir(dir, (err, files) => {
|
||||
if (err) reject(err);
|
||||
resolve(files);
|
||||
});
|
||||
})
|
||||
.then(
|
||||
(files) =>
|
||||
assertEqualsArrayAnyOrder(
|
||||
files,
|
||||
["file1.txt", "some_dir", "file2.txt"],
|
||||
),
|
||||
() => fail(),
|
||||
)
|
||||
.finally(() => Deno.removeSync(dir, { recursive: true }));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: reading empty the directory",
|
||||
fn() {
|
||||
const dir = Deno.makeTempDirSync();
|
||||
assertEquals(readdirSync(dir), []);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: reading non-empty directory",
|
||||
fn() {
|
||||
const dir = Deno.makeTempDirSync();
|
||||
Deno.writeTextFileSync(join(dir, "file1.txt"), "hi");
|
||||
Deno.writeTextFileSync(join(dir, "file2.txt"), "hi");
|
||||
Deno.mkdirSync(join(dir, "some_dir"));
|
||||
assertEqualsArrayAnyOrder(
|
||||
readdirSync(dir),
|
||||
["file1.txt", "some_dir", "file2.txt"],
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] readdir callback isn't called twice if error is thrown", async () => {
|
||||
// The correct behaviour is not to catch any errors thrown,
|
||||
// but that means there'll be an uncaught error and the test will fail.
|
||||
// So the only way to test this is to spawn a subprocess, and succeed if it has a non-zero exit code.
|
||||
// (assertRejects won't work because there's no way to catch the error.)
|
||||
const tempDir = await Deno.makeTempDir();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { readdir } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `readdir(${JSON.stringify(tempDir)}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempDir);
|
||||
},
|
||||
});
|
||||
});
|
78
cli/tests/unit_node/_fs/_fs_readlink_test.ts
Normal file
78
cli/tests/unit_node/_fs/_fs_readlink_test.ts
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { readlink, readlinkSync } from "node:fs";
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import * as path from "../../../../test_util/std/path/mod.ts";
|
||||
|
||||
const testDir = Deno.makeTempDirSync();
|
||||
const oldname = path.join(testDir, "oldname");
|
||||
const newname = path.join(testDir, "newname");
|
||||
|
||||
if (Deno.build.os === "windows") {
|
||||
Deno.symlinkSync(oldname, newname, { type: "file" });
|
||||
} else {
|
||||
Deno.symlinkSync(oldname, newname);
|
||||
}
|
||||
|
||||
Deno.test({
|
||||
name: "readlinkSuccess",
|
||||
async fn() {
|
||||
const data = await new Promise((res, rej) => {
|
||||
readlink(newname, (err, data) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
}
|
||||
res(data);
|
||||
});
|
||||
});
|
||||
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, oldname);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "readlinkEncodeBufferSuccess",
|
||||
async fn() {
|
||||
const data = await new Promise((res, rej) => {
|
||||
readlink(newname, { encoding: "buffer" }, (err, data) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
}
|
||||
res(data);
|
||||
});
|
||||
});
|
||||
|
||||
assert(data instanceof Uint8Array);
|
||||
assertEquals(new TextDecoder().decode(data as Uint8Array), oldname);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "readlinkSyncSuccess",
|
||||
fn() {
|
||||
const data = readlinkSync(newname);
|
||||
assertEquals(typeof data, "string");
|
||||
assertEquals(data as string, oldname);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "readlinkEncodeBufferSuccess",
|
||||
fn() {
|
||||
const data = readlinkSync(newname, { encoding: "buffer" });
|
||||
assert(data instanceof Uint8Array);
|
||||
assertEquals(new TextDecoder().decode(data as Uint8Array), oldname);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] readlink callback isn't called twice if error is thrown", async () => {
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { readlink } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `readlink(${JSON.stringify(newname)}, `,
|
||||
});
|
||||
});
|
55
cli/tests/unit_node/_fs/_fs_realpath_test.ts
Normal file
55
cli/tests/unit_node/_fs/_fs_realpath_test.ts
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import * as path from "../../../../test_util/std/path/mod.ts";
|
||||
import { assertEquals } from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { realpath, realpathSync } from "node:fs";
|
||||
|
||||
Deno.test("realpath", async function () {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const tempFileAlias = tempFile + ".alias";
|
||||
await Deno.symlink(tempFile, tempFileAlias);
|
||||
const realPath = await new Promise((resolve, reject) => {
|
||||
realpath(tempFile, (err, path) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(path);
|
||||
});
|
||||
});
|
||||
const realSymLinkPath = await new Promise((resolve, reject) => {
|
||||
realpath(tempFileAlias, (err, path) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(path);
|
||||
});
|
||||
});
|
||||
assertEquals(realPath, realSymLinkPath);
|
||||
});
|
||||
|
||||
Deno.test("realpathSync", function () {
|
||||
const tempFile = Deno.makeTempFileSync();
|
||||
const tempFileAlias = tempFile + ".alias";
|
||||
Deno.symlinkSync(tempFile, tempFileAlias);
|
||||
const realPath = realpathSync(tempFile);
|
||||
const realSymLinkPath = realpathSync(tempFileAlias);
|
||||
assertEquals(realPath, realSymLinkPath);
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] realpath callback isn't called twice if error is thrown", async () => {
|
||||
const tempDir = await Deno.makeTempDir();
|
||||
const tempFile = path.join(tempDir, "file.txt");
|
||||
const linkFile = path.join(tempDir, "link.txt");
|
||||
await Deno.writeTextFile(tempFile, "hello world");
|
||||
await Deno.symlink(tempFile, linkFile, { type: "file" });
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { realpath } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `realpath(${JSON.stringify(`${tempDir}/link.txt`)}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempDir, { recursive: true });
|
||||
},
|
||||
});
|
||||
});
|
55
cli/tests/unit_node/_fs/_fs_rename_test.ts
Normal file
55
cli/tests/unit_node/_fs/_fs_rename_test.ts
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { rename, renameSync } from "node:fs";
|
||||
import { existsSync } from "node:fs";
|
||||
import { join, parse } from "../../../../test_util/std/path/mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: renaming a file",
|
||||
async fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
const newPath = join(parse(file).dir, `${parse(file).base}_renamed`);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
rename(file, newPath, (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
assertEquals(existsSync(newPath), true);
|
||||
assertEquals(existsSync(file), false);
|
||||
}, () => fail())
|
||||
.finally(() => {
|
||||
if (existsSync(file)) Deno.removeSync(file);
|
||||
if (existsSync(newPath)) Deno.removeSync(newPath);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: renaming a file",
|
||||
fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
const newPath = join(parse(file).dir, `${parse(file).base}_renamed`);
|
||||
renameSync(file, newPath);
|
||||
assertEquals(existsSync(newPath), true);
|
||||
assertEquals(existsSync(file), false);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] rename callback isn't called twice if error is thrown", async () => {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { rename } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `rename(${JSON.stringify(tempFile)},
|
||||
${JSON.stringify(`${tempFile}.newname`)}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(`${tempFile}.newname`);
|
||||
},
|
||||
});
|
||||
});
|
158
cli/tests/unit_node/_fs/_fs_rm_test.ts
Normal file
158
cli/tests/unit_node/_fs/_fs_rm_test.ts
Normal file
@ -0,0 +1,158 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
assertRejects,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { rm, rmSync } from "node:fs";
|
||||
import { closeSync, existsSync } from "node:fs";
|
||||
import { join } from "../../../../test_util/std/path/mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: removing empty folder",
|
||||
async fn() {
|
||||
const dir = Deno.makeTempDirSync();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
rm(dir, { recursive: true }, (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
.then(() => assertEquals(existsSync(dir), false), () => fail())
|
||||
.finally(() => {
|
||||
if (existsSync(dir)) Deno.removeSync(dir);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
function closeRes(before: Deno.ResourceMap, after: Deno.ResourceMap) {
|
||||
for (const key in after) {
|
||||
if (!before[key]) {
|
||||
try {
|
||||
closeSync(Number(key));
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: removing non-empty folder",
|
||||
async fn() {
|
||||
const rBefore = Deno.resources();
|
||||
const dir = Deno.makeTempDirSync();
|
||||
Deno.createSync(join(dir, "file1.txt"));
|
||||
Deno.createSync(join(dir, "file2.txt"));
|
||||
Deno.mkdirSync(join(dir, "some_dir"));
|
||||
Deno.createSync(join(dir, "some_dir", "file.txt"));
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
rm(dir, { recursive: true }, (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
.then(() => assertEquals(existsSync(dir), false), () => fail())
|
||||
.finally(() => {
|
||||
if (existsSync(dir)) Deno.removeSync(dir, { recursive: true });
|
||||
const rAfter = Deno.resources();
|
||||
closeRes(rBefore, rAfter);
|
||||
});
|
||||
},
|
||||
ignore: Deno.build.os === "windows",
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: removing a file",
|
||||
async fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
rm(file, (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
assertEquals(existsSync(file), false);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: remove should fail if target does not exist",
|
||||
async fn() {
|
||||
const removePromise = new Promise<void>((resolve, reject) => {
|
||||
rm("/path/to/noexist.text", (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
await assertRejects(() => removePromise, Error);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"ASYNC: remove should not fail if target does not exist and force option is true",
|
||||
async fn() {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
rm("/path/to/noexist.text", { force: true }, (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: removing empty folder",
|
||||
fn() {
|
||||
const dir = Deno.makeTempDirSync();
|
||||
rmSync(dir, { recursive: true });
|
||||
assertEquals(existsSync(dir), false);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: removing non-empty folder",
|
||||
fn() {
|
||||
const rBefore = Deno.resources();
|
||||
const dir = Deno.makeTempDirSync();
|
||||
Deno.createSync(join(dir, "file1.txt"));
|
||||
Deno.createSync(join(dir, "file2.txt"));
|
||||
Deno.mkdirSync(join(dir, "some_dir"));
|
||||
Deno.createSync(join(dir, "some_dir", "file.txt"));
|
||||
rmSync(dir, { recursive: true });
|
||||
assertEquals(existsSync(dir), false);
|
||||
// closing resources
|
||||
const rAfter = Deno.resources();
|
||||
closeRes(rBefore, rAfter);
|
||||
},
|
||||
ignore: Deno.build.os === "windows",
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: removing a file",
|
||||
fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
|
||||
rmSync(file);
|
||||
|
||||
assertEquals(existsSync(file), false);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: remove should fail if target does not exist",
|
||||
fn() {
|
||||
assertThrows(() => rmSync("/path/to/noexist.text"), Error);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"SYNC: remove should not fail if target does not exist and force option is true",
|
||||
fn() {
|
||||
rmSync("/path/to/noexist.text", { force: true });
|
||||
},
|
||||
});
|
104
cli/tests/unit_node/_fs/_fs_rmdir_test.ts
Normal file
104
cli/tests/unit_node/_fs/_fs_rmdir_test.ts
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { rmdir, rmdirSync } from "node:fs";
|
||||
import { closeSync } from "node:fs";
|
||||
import { existsSync } from "node:fs";
|
||||
import { join } from "../../../../test_util/std/path/mod.ts";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: removing empty folder",
|
||||
async fn() {
|
||||
const dir = Deno.makeTempDirSync();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
rmdir(dir, (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
.then(() => assertEquals(existsSync(dir), false), () => fail())
|
||||
.finally(() => {
|
||||
if (existsSync(dir)) Deno.removeSync(dir);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: removing empty folder",
|
||||
fn() {
|
||||
const dir = Deno.makeTempDirSync();
|
||||
rmdirSync(dir);
|
||||
assertEquals(existsSync(dir), false);
|
||||
},
|
||||
});
|
||||
|
||||
function closeRes(before: Deno.ResourceMap, after: Deno.ResourceMap) {
|
||||
for (const key in after) {
|
||||
if (!before[key]) {
|
||||
try {
|
||||
closeSync(Number(key));
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: removing non-empty folder",
|
||||
async fn() {
|
||||
const rBefore = Deno.resources();
|
||||
const dir = Deno.makeTempDirSync();
|
||||
Deno.createSync(join(dir, "file1.txt"));
|
||||
Deno.createSync(join(dir, "file2.txt"));
|
||||
Deno.mkdirSync(join(dir, "some_dir"));
|
||||
Deno.createSync(join(dir, "some_dir", "file.txt"));
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
rmdir(dir, { recursive: true }, (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
.then(() => assertEquals(existsSync(dir), false), () => fail())
|
||||
.finally(() => {
|
||||
if (existsSync(dir)) Deno.removeSync(dir, { recursive: true });
|
||||
const rAfter = Deno.resources();
|
||||
closeRes(rBefore, rAfter);
|
||||
});
|
||||
},
|
||||
ignore: Deno.build.os === "windows",
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: removing non-empty folder",
|
||||
fn() {
|
||||
const rBefore = Deno.resources();
|
||||
const dir = Deno.makeTempDirSync();
|
||||
Deno.createSync(join(dir, "file1.txt"));
|
||||
Deno.createSync(join(dir, "file2.txt"));
|
||||
Deno.mkdirSync(join(dir, "some_dir"));
|
||||
Deno.createSync(join(dir, "some_dir", "file.txt"));
|
||||
rmdirSync(dir, { recursive: true });
|
||||
assertEquals(existsSync(dir), false);
|
||||
// closing resources
|
||||
const rAfter = Deno.resources();
|
||||
closeRes(rBefore, rAfter);
|
||||
},
|
||||
ignore: Deno.build.os === "windows",
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] rmdir callback isn't called twice if error is thrown", async () => {
|
||||
// The correct behaviour is not to catch any errors thrown,
|
||||
// but that means there'll be an uncaught error and the test will fail.
|
||||
// So the only way to test this is to spawn a subprocess, and succeed if it has a non-zero exit code.
|
||||
// (assertRejects won't work because there's no way to catch the error.)
|
||||
const tempDir = await Deno.makeTempDir();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { rmdir } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `rmdir(${JSON.stringify(tempDir)}, `,
|
||||
});
|
||||
});
|
134
cli/tests/unit_node/_fs/_fs_stat_test.ts
Normal file
134
cli/tests/unit_node/_fs/_fs_stat_test.ts
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { BigIntStats, stat, Stats, statSync } from "node:fs";
|
||||
import {
|
||||
assertEquals,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
|
||||
export function assertStats(actual: Stats, expected: Deno.FileInfo) {
|
||||
assertEquals(actual.dev, expected.dev);
|
||||
assertEquals(actual.gid, expected.gid);
|
||||
assertEquals(actual.size, expected.size);
|
||||
assertEquals(actual.blksize, expected.blksize);
|
||||
assertEquals(actual.blocks, expected.blocks);
|
||||
assertEquals(actual.ino, expected.ino);
|
||||
assertEquals(actual.gid, expected.gid);
|
||||
assertEquals(actual.mode, expected.mode);
|
||||
assertEquals(actual.nlink, expected.nlink);
|
||||
assertEquals(actual.rdev, expected.rdev);
|
||||
assertEquals(actual.uid, expected.uid);
|
||||
assertEquals(actual.atime?.getTime(), expected.atime?.getTime());
|
||||
assertEquals(actual.mtime?.getTime(), expected.mtime?.getTime());
|
||||
assertEquals(actual.birthtime?.getTime(), expected.birthtime?.getTime());
|
||||
assertEquals(actual.atimeMs ?? undefined, expected.atime?.getTime());
|
||||
assertEquals(actual.mtimeMs ?? undefined, expected.mtime?.getTime());
|
||||
assertEquals(actual.birthtimeMs ?? undefined, expected.birthtime?.getTime());
|
||||
assertEquals(actual.isFile(), expected.isFile);
|
||||
assertEquals(actual.isDirectory(), expected.isDirectory);
|
||||
assertEquals(actual.isSymbolicLink(), expected.isSymlink);
|
||||
}
|
||||
|
||||
function toBigInt(num?: number | null) {
|
||||
if (num === undefined || num === null) return null;
|
||||
return BigInt(num);
|
||||
}
|
||||
|
||||
export function assertStatsBigInt(
|
||||
actual: BigIntStats,
|
||||
expected: Deno.FileInfo,
|
||||
) {
|
||||
assertEquals(actual.dev, toBigInt(expected.dev));
|
||||
assertEquals(actual.gid, toBigInt(expected.gid));
|
||||
assertEquals(actual.size, toBigInt(expected.size));
|
||||
assertEquals(actual.blksize, toBigInt(expected.blksize));
|
||||
assertEquals(actual.blocks, toBigInt(expected.blocks));
|
||||
assertEquals(actual.ino, toBigInt(expected.ino));
|
||||
assertEquals(actual.gid, toBigInt(expected.gid));
|
||||
assertEquals(actual.mode, toBigInt(expected.mode));
|
||||
assertEquals(actual.nlink, toBigInt(expected.nlink));
|
||||
assertEquals(actual.rdev, toBigInt(expected.rdev));
|
||||
assertEquals(actual.uid, toBigInt(expected.uid));
|
||||
assertEquals(actual.atime?.getTime(), expected.atime?.getTime());
|
||||
assertEquals(actual.mtime?.getTime(), expected.mtime?.getTime());
|
||||
assertEquals(actual.birthtime?.getTime(), expected.birthtime?.getTime());
|
||||
assertEquals(
|
||||
actual.atimeMs === null ? undefined : Number(actual.atimeMs),
|
||||
expected.atime?.getTime(),
|
||||
);
|
||||
assertEquals(
|
||||
actual.mtimeMs === null ? undefined : Number(actual.mtimeMs),
|
||||
expected.mtime?.getTime(),
|
||||
);
|
||||
assertEquals(
|
||||
actual.birthtimeMs === null ? undefined : Number(actual.birthtimeMs),
|
||||
expected.birthtime?.getTime(),
|
||||
);
|
||||
assertEquals(actual.atimeNs === null, actual.atime === null);
|
||||
assertEquals(actual.mtimeNs === null, actual.mtime === null);
|
||||
assertEquals(actual.birthtimeNs === null, actual.birthtime === null);
|
||||
assertEquals(actual.isFile(), expected.isFile);
|
||||
assertEquals(actual.isDirectory(), expected.isDirectory);
|
||||
assertEquals(actual.isSymbolicLink(), expected.isSymlink);
|
||||
}
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: get a file Stats",
|
||||
async fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
await new Promise<Stats>((resolve, reject) => {
|
||||
stat(file, (err, stat) => {
|
||||
if (err) reject(err);
|
||||
resolve(stat);
|
||||
});
|
||||
})
|
||||
.then((stat) => assertStats(stat, Deno.statSync(file)), () => fail())
|
||||
.finally(() => Deno.removeSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: get a file Stats",
|
||||
fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
assertStats(statSync(file), Deno.statSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: get a file BigInt Stats",
|
||||
async fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
await new Promise<BigIntStats>((resolve, reject) => {
|
||||
stat(file, { bigint: true }, (err, stat) => {
|
||||
if (err) reject(err);
|
||||
resolve(stat);
|
||||
});
|
||||
})
|
||||
.then(
|
||||
(stat) => assertStatsBigInt(stat, Deno.statSync(file)),
|
||||
() => fail(),
|
||||
)
|
||||
.finally(() => Deno.removeSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: get a file BigInt Stats",
|
||||
fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
assertStatsBigInt(statSync(file, { bigint: true }), Deno.statSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] stat callback isn't called twice if error is thrown", async () => {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { stat } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `stat(${JSON.stringify(tempFile)}, `,
|
||||
async cleanup() {
|
||||
await Deno.remove(tempFile);
|
||||
},
|
||||
});
|
||||
});
|
111
cli/tests/unit_node/_fs/_fs_symlink_test.ts
Normal file
111
cli/tests/unit_node/_fs/_fs_symlink_test.ts
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assert,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { symlink, symlinkSync } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: no callback function results in Error",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
// @ts-expect-error Argument of type 'string' is not assignable to parameter of type 'NoParamCallback'
|
||||
symlink("some/path", "some/other/path", "dir");
|
||||
},
|
||||
Error,
|
||||
"No callback function supplied",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: create symlink point to a file",
|
||||
async fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
const linkedFile: string = file + ".link";
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
symlink(file, linkedFile, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const stat = Deno.lstatSync(linkedFile);
|
||||
assert(stat.isSymlink);
|
||||
},
|
||||
() => {
|
||||
fail("Expected to succeed");
|
||||
},
|
||||
)
|
||||
.finally(() => {
|
||||
Deno.removeSync(file);
|
||||
Deno.removeSync(linkedFile);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: create symlink point to a dir",
|
||||
async fn() {
|
||||
const dir: string = Deno.makeTempDirSync();
|
||||
const linkedDir: string = dir + ".link";
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
symlink(dir, linkedDir, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const stat = Deno.lstatSync(linkedDir);
|
||||
assert(stat.isSymlink);
|
||||
},
|
||||
() => {
|
||||
fail("Expected to succeed");
|
||||
},
|
||||
)
|
||||
.finally(() => {
|
||||
Deno.removeSync(dir);
|
||||
Deno.removeSync(linkedDir);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: create symlink point to a file",
|
||||
fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
const linkedFile: string = file + ".link";
|
||||
|
||||
try {
|
||||
symlinkSync(file, linkedFile);
|
||||
const stat = Deno.lstatSync(linkedFile);
|
||||
assert(stat.isSymlink);
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
Deno.removeSync(linkedFile);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: create symlink point to a dir",
|
||||
fn() {
|
||||
const dir: string = Deno.makeTempDirSync();
|
||||
const linkedDir: string = dir + ".link";
|
||||
|
||||
try {
|
||||
symlinkSync(dir, linkedDir);
|
||||
const stat = Deno.lstatSync(linkedDir);
|
||||
assert(stat.isSymlink);
|
||||
} finally {
|
||||
Deno.removeSync(dir);
|
||||
Deno.removeSync(linkedDir);
|
||||
}
|
||||
},
|
||||
});
|
99
cli/tests/unit_node/_fs/_fs_truncate_test.ts
Normal file
99
cli/tests/unit_node/_fs/_fs_truncate_test.ts
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { truncate, truncateSync } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: no callback function results in Error",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
// @ts-expect-error Argument of type 'number' is not assignable to parameter of type 'NoParamCallback'
|
||||
truncate("some/path", 0);
|
||||
},
|
||||
Error,
|
||||
"No callback function supplied",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: truncate entire file contents",
|
||||
async fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
await Deno.writeFile(file, new TextEncoder().encode("hello world"));
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
truncate(file, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.size, 0);
|
||||
},
|
||||
() => {
|
||||
fail("No error expected");
|
||||
},
|
||||
)
|
||||
.finally(() => Deno.removeSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: truncate file to a size of precisely len bytes",
|
||||
async fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
await Deno.writeFile(file, new TextEncoder().encode("hello world"));
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
truncate(file, 3, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.size, 3);
|
||||
},
|
||||
() => {
|
||||
fail("No error expected");
|
||||
},
|
||||
)
|
||||
.finally(() => Deno.removeSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: truncate entire file contents",
|
||||
fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
try {
|
||||
truncateSync(file);
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.size, 0);
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: truncate file to a size of precisely len bytes",
|
||||
fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
try {
|
||||
truncateSync(file, 3);
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.size, 3);
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
}
|
||||
},
|
||||
});
|
43
cli/tests/unit_node/_fs/_fs_unlink_test.ts
Normal file
43
cli/tests/unit_node/_fs/_fs_unlink_test.ts
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { existsSync } from "node:fs";
|
||||
import { assertCallbackErrorUncaught } from "../_test_utils.ts";
|
||||
import { unlink, unlinkSync } from "node:fs";
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: deleting a file",
|
||||
async fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
unlink(file, (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
.then(() => assertEquals(existsSync(file), false), () => fail())
|
||||
.finally(() => {
|
||||
if (existsSync(file)) Deno.removeSync(file);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: Test deleting a file",
|
||||
fn() {
|
||||
const file = Deno.makeTempFileSync();
|
||||
unlinkSync(file);
|
||||
assertEquals(existsSync(file), false);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("[std/node/fs] unlink callback isn't called twice if error is thrown", async () => {
|
||||
const tempFile = await Deno.makeTempFile();
|
||||
const importUrl = new URL("node:fs", import.meta.url);
|
||||
await assertCallbackErrorUncaught({
|
||||
prelude: `import { unlink } from ${JSON.stringify(importUrl)}`,
|
||||
invocation: `unlink(${JSON.stringify(tempFile)}, `,
|
||||
});
|
||||
});
|
104
cli/tests/unit_node/_fs/_fs_utimes_test.ts
Normal file
104
cli/tests/unit_node/_fs/_fs_utimes_test.ts
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { utimes, utimesSync } from "node:fs";
|
||||
|
||||
const randomDate = new Date(Date.now() + 1000);
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"ASYNC: change the file system timestamps of the object referenced by path",
|
||||
async fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
utimes(file, randomDate, randomDate, (err: Error | null) => {
|
||||
if (err !== null) reject();
|
||||
else resolve();
|
||||
});
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
assertEquals(fileInfo.mtime, randomDate);
|
||||
assertEquals(fileInfo.mtime, randomDate);
|
||||
},
|
||||
() => {
|
||||
fail("No error expected");
|
||||
},
|
||||
)
|
||||
.finally(() => Deno.removeSync(file));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: should throw error if atime is infinity",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
utimes("some/path", Infinity, 0, (_err: Error | null) => {});
|
||||
},
|
||||
Error,
|
||||
"invalid atime, must not be infinity or NaN",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ASYNC: should throw error if atime is NaN",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
utimes("some/path", "some string", 0, (_err: Error | null) => {});
|
||||
},
|
||||
Error,
|
||||
"invalid atime, must not be infinity or NaN",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name:
|
||||
"SYNC: change the file system timestamps of the object referenced by path",
|
||||
fn() {
|
||||
const file: string = Deno.makeTempFileSync();
|
||||
try {
|
||||
utimesSync(file, randomDate, randomDate);
|
||||
|
||||
const fileInfo: Deno.FileInfo = Deno.lstatSync(file);
|
||||
|
||||
assertEquals(fileInfo.mtime, randomDate);
|
||||
} finally {
|
||||
Deno.removeSync(file);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: should throw error if atime is NaN",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
utimesSync("some/path", "some string", 0);
|
||||
},
|
||||
Error,
|
||||
"invalid atime, must not be infinity or NaN",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "SYNC: should throw error if atime is Infinity",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
utimesSync("some/path", Infinity, 0);
|
||||
},
|
||||
Error,
|
||||
"invalid atime, must not be infinity or NaN",
|
||||
);
|
||||
},
|
||||
});
|
53
cli/tests/unit_node/_fs/_fs_write_test.ts
Normal file
53
cli/tests/unit_node/_fs/_fs_write_test.ts
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { write, writeSync } from "node:fs";
|
||||
import { assertEquals } from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { Buffer } from "node:buffer";
|
||||
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
|
||||
Deno.test({
|
||||
name: "Data is written to the file with the correct length",
|
||||
async fn() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
const file: Deno.FsFile = await Deno.open(tempFile, {
|
||||
create: true,
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
const buffer = Buffer.from("hello world");
|
||||
const bytesWrite = await new Promise((resolve, reject) => {
|
||||
write(file.rid, buffer, 0, 5, (err: unknown, nwritten: number) => {
|
||||
if (err) return reject(err);
|
||||
resolve(nwritten);
|
||||
});
|
||||
});
|
||||
Deno.close(file.rid);
|
||||
|
||||
const data = await Deno.readFile(tempFile);
|
||||
await Deno.remove(tempFile);
|
||||
|
||||
assertEquals(bytesWrite, 5);
|
||||
assertEquals(decoder.decode(data), "hello");
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Data is written synchronously to the file with the correct length",
|
||||
fn() {
|
||||
const tempFile: string = Deno.makeTempFileSync();
|
||||
const file: Deno.FsFile = Deno.openSync(tempFile, {
|
||||
create: true,
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
const buffer = Buffer.from("hello world");
|
||||
const bytesWrite = writeSync(file.rid, buffer, 0, 5);
|
||||
Deno.close(file.rid);
|
||||
|
||||
const data = Deno.readFileSync(tempFile);
|
||||
Deno.removeSync(tempFile);
|
||||
|
||||
assertEquals(bytesWrite, 5);
|
||||
assertEquals(decoder.decode(data), "hello");
|
||||
},
|
||||
});
|
1
cli/tests/unit_node/_fs/testdata/hello.txt
vendored
Normal file
1
cli/tests/unit_node/_fs/testdata/hello.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
hello world
|
43
cli/tests/unit_node/_test_utils.ts
Normal file
43
cli/tests/unit_node/_test_utils.ts
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import {
|
||||
assert,
|
||||
assertStringIncludes,
|
||||
} from "../../../test_util/std/testing/asserts.ts";
|
||||
|
||||
/** Asserts that an error thrown in a callback will not be wrongly caught. */
|
||||
export async function assertCallbackErrorUncaught(
|
||||
{ prelude, invocation, cleanup }: {
|
||||
/** Any code which needs to run before the actual invocation (notably, any import statements). */
|
||||
prelude?: string;
|
||||
/**
|
||||
* The start of the invocation of the function, e.g. `open("foo.txt", `.
|
||||
* The callback will be added after it.
|
||||
*/
|
||||
invocation: string;
|
||||
/** Called after the subprocess is finished but before running the assertions, e.g. to clean up created files. */
|
||||
cleanup?: () => Promise<void> | void;
|
||||
},
|
||||
) {
|
||||
// Since the error has to be uncaught, and that will kill the Deno process,
|
||||
// the only way to test this is to spawn a subprocess.
|
||||
const p = new Deno.Command(Deno.execPath(), {
|
||||
args: [
|
||||
"eval",
|
||||
"--unstable",
|
||||
`${prelude ?? ""}
|
||||
|
||||
${invocation}(err) => {
|
||||
// If the bug is present and the callback is called again with an error,
|
||||
// don't throw another error, so if the subprocess fails we know it had the correct behaviour.
|
||||
if (!err) throw new Error("success");
|
||||
});`,
|
||||
],
|
||||
stderr: "piped",
|
||||
});
|
||||
const { stderr, success } = await p.output();
|
||||
const error = new TextDecoder().decode(stderr);
|
||||
await cleanup?.();
|
||||
assert(!success);
|
||||
assertStringIncludes(error, "Error: success");
|
||||
}
|
Loading…
Reference in New Issue
Block a user