test(ext/node): port _fs tests from std/node (#18262)

Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
This commit is contained in:
Max Dahlgren 2023-03-20 03:10:39 +11:00 committed by GitHub
parent 3b1cb8af69
commit bf149d047f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 2800 additions and 2 deletions

View File

@ -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(() => {

View 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);
},
});
});

View 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);
},
});
},
});

View 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);
},
});
},
});

View 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);
},
});
});

View 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 });
},
});
});

View 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");
});

View 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);
}
},
});

View 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);
}
},
});

View 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);
}
},
});

View 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);
}
},
});

View 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",
);
},
});

View 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 });
},
});
});

View 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);
},
});
});

View 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 });
},
});
});

View 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));
},
});

View 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);
});

View 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);
},
});
});

View 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);
},
});
});

View 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)}, `,
});
});

View 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 });
},
});
});

View 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`);
},
});
});

View 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 });
},
});

View 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)}, `,
});
});

View 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);
},
});
});

View 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);
}
},
});

View 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);
}
},
});

View 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)}, `,
});
});

View 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",
);
},
});

View 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");
},
});

View File

@ -0,0 +1 @@
hello world

View 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");
}