mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 09:31:22 -05:00
feat(std/node): fs.writefile / fs.promises.writeFile (#5054)
This commit is contained in:
parent
5f67a202ff
commit
f0aea98c85
10 changed files with 522 additions and 121 deletions
|
@ -1,5 +1,10 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { FileOptions, isFileOptions, CallbackWithError } from "./_fs_common.ts";
|
||||
import {
|
||||
WriteFileOptions,
|
||||
isFileOptions,
|
||||
CallbackWithError,
|
||||
getOpenOptions,
|
||||
} from "./_fs_common.ts";
|
||||
import { notImplemented } from "../_utils.ts";
|
||||
import { fromFileUrl } from "../path.ts";
|
||||
|
||||
|
@ -10,13 +15,13 @@ import { fromFileUrl } from "../path.ts";
|
|||
export function appendFile(
|
||||
pathOrRid: string | number | URL,
|
||||
data: string,
|
||||
optionsOrCallback: string | FileOptions | CallbackWithError,
|
||||
optionsOrCallback: string | WriteFileOptions | CallbackWithError,
|
||||
callback?: CallbackWithError
|
||||
): void {
|
||||
pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid;
|
||||
const callbackFn: CallbackWithError | undefined =
|
||||
optionsOrCallback instanceof Function ? optionsOrCallback : callback;
|
||||
const options: string | FileOptions | undefined =
|
||||
const options: string | WriteFileOptions | undefined =
|
||||
optionsOrCallback instanceof Function ? undefined : optionsOrCallback;
|
||||
if (!callbackFn) {
|
||||
throw new Error("No callback function supplied");
|
||||
|
@ -74,7 +79,7 @@ function closeRidIfNecessary(isPathString: boolean, rid: number): void {
|
|||
export function appendFileSync(
|
||||
pathOrRid: string | number | URL,
|
||||
data: string,
|
||||
options?: string | FileOptions
|
||||
options?: string | WriteFileOptions
|
||||
): void {
|
||||
let rid = -1;
|
||||
|
||||
|
@ -110,7 +115,7 @@ export function appendFileSync(
|
|||
}
|
||||
|
||||
function validateEncoding(
|
||||
encodingOption: string | FileOptions | undefined
|
||||
encodingOption: string | WriteFileOptions | undefined
|
||||
): void {
|
||||
if (!encodingOption) return;
|
||||
|
||||
|
@ -122,80 +127,3 @@ function validateEncoding(
|
|||
throw new Error("Only 'utf8' encoding is currently supported");
|
||||
}
|
||||
}
|
||||
|
||||
function getOpenOptions(flag: string | undefined): Deno.OpenOptions {
|
||||
if (!flag) {
|
||||
return { create: true, append: true };
|
||||
}
|
||||
|
||||
let openOptions: Deno.OpenOptions;
|
||||
switch (flag) {
|
||||
case "a": {
|
||||
// 'a': Open file for appending. The file is created if it does not exist.
|
||||
openOptions = { create: true, append: true };
|
||||
break;
|
||||
}
|
||||
case "ax": {
|
||||
// 'ax': Like 'a' but fails if the path exists.
|
||||
openOptions = { createNew: true, write: true, append: true };
|
||||
break;
|
||||
}
|
||||
case "a+": {
|
||||
// 'a+': Open file for reading and appending. The file is created if it does not exist.
|
||||
openOptions = { read: true, create: true, append: true };
|
||||
break;
|
||||
}
|
||||
case "ax+": {
|
||||
// 'ax+': Like 'a+' but fails if the path exists.
|
||||
openOptions = { read: true, createNew: true, append: true };
|
||||
break;
|
||||
}
|
||||
case "r": {
|
||||
// 'r': Open file for reading. An exception occurs if the file does not exist.
|
||||
openOptions = { read: true };
|
||||
break;
|
||||
}
|
||||
case "r+": {
|
||||
// 'r+': Open file for reading and writing. An exception occurs if the file does not exist.
|
||||
openOptions = { read: true, write: true };
|
||||
break;
|
||||
}
|
||||
case "w": {
|
||||
// 'w': Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
|
||||
openOptions = { create: true, write: true, truncate: true };
|
||||
break;
|
||||
}
|
||||
case "wx": {
|
||||
// 'wx': Like 'w' but fails if the path exists.
|
||||
openOptions = { createNew: true, write: true };
|
||||
break;
|
||||
}
|
||||
case "w+": {
|
||||
// 'w+': Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
|
||||
openOptions = { create: true, write: true, truncate: true, read: true };
|
||||
break;
|
||||
}
|
||||
case "wx+": {
|
||||
// 'wx+': Like 'w+' but fails if the path exists.
|
||||
openOptions = { createNew: true, write: true, read: true };
|
||||
break;
|
||||
}
|
||||
case "as": {
|
||||
// 'as': Open file for appending in synchronous mode. The file is created if it does not exist.
|
||||
openOptions = { create: true, append: true };
|
||||
}
|
||||
case "as+": {
|
||||
// 'as+': Open file for reading and appending in synchronous mode. The file is created if it does not exist.
|
||||
openOptions = { create: true, read: true, append: true };
|
||||
}
|
||||
case "rs+": {
|
||||
// 'rs+': Open file for reading and writing in synchronous mode. Instructs the operating system to bypass the local file system cache.
|
||||
openOptions = { create: true, read: true, write: true };
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unrecognized file system flag: ${flag}`);
|
||||
}
|
||||
}
|
||||
|
||||
return openOptions;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,137 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
export type CallbackWithError = (err?: Error) => void;
|
||||
import { notImplemented } from "../_utils.ts";
|
||||
|
||||
export type CallbackWithError = (err?: Error | null) => void;
|
||||
|
||||
export interface FileOptions {
|
||||
encoding?: string;
|
||||
mode?: number;
|
||||
flag?: string;
|
||||
}
|
||||
|
||||
export interface WriteFileOptions extends FileOptions {
|
||||
mode?: number;
|
||||
}
|
||||
|
||||
export function isFileOptions(
|
||||
fileOptions: string | FileOptions | undefined
|
||||
fileOptions: string | WriteFileOptions | undefined
|
||||
): fileOptions is FileOptions {
|
||||
if (!fileOptions) return false;
|
||||
|
||||
return (
|
||||
(fileOptions as FileOptions).encoding != undefined ||
|
||||
(fileOptions as FileOptions).flag != undefined ||
|
||||
(fileOptions as FileOptions).mode != undefined
|
||||
(fileOptions as WriteFileOptions).mode != undefined
|
||||
);
|
||||
}
|
||||
|
||||
export function getEncoding(
|
||||
optOrCallback?: FileOptions | WriteFileOptions | Function | string
|
||||
): string | null {
|
||||
if (!optOrCallback || typeof optOrCallback === "function") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const encoding =
|
||||
typeof optOrCallback === "string" ? optOrCallback : optOrCallback.encoding;
|
||||
if (!encoding) return null;
|
||||
if (encoding === "utf8" || encoding === "utf-8") {
|
||||
return "utf8";
|
||||
}
|
||||
if (encoding === "buffer") {
|
||||
return "buffer";
|
||||
}
|
||||
|
||||
const notImplementedEncodings = [
|
||||
"utf16le",
|
||||
"latin1",
|
||||
"base64",
|
||||
"hex",
|
||||
"ascii",
|
||||
"binary",
|
||||
"ucs2",
|
||||
];
|
||||
|
||||
if (notImplementedEncodings.includes(encoding)) {
|
||||
notImplemented(`"${encoding}" encoding`);
|
||||
}
|
||||
|
||||
throw new Error(`The value "${encoding}" is invalid for option "encoding"`);
|
||||
}
|
||||
|
||||
export function getOpenOptions(flag: string | undefined): Deno.OpenOptions {
|
||||
if (!flag) {
|
||||
return { create: true, append: true };
|
||||
}
|
||||
|
||||
let openOptions: Deno.OpenOptions;
|
||||
switch (flag) {
|
||||
case "a": {
|
||||
// 'a': Open file for appending. The file is created if it does not exist.
|
||||
openOptions = { create: true, append: true };
|
||||
break;
|
||||
}
|
||||
case "ax": {
|
||||
// 'ax': Like 'a' but fails if the path exists.
|
||||
openOptions = { createNew: true, write: true, append: true };
|
||||
break;
|
||||
}
|
||||
case "a+": {
|
||||
// 'a+': Open file for reading and appending. The file is created if it does not exist.
|
||||
openOptions = { read: true, create: true, append: true };
|
||||
break;
|
||||
}
|
||||
case "ax+": {
|
||||
// 'ax+': Like 'a+' but fails if the path exists.
|
||||
openOptions = { read: true, createNew: true, append: true };
|
||||
break;
|
||||
}
|
||||
case "r": {
|
||||
// 'r': Open file for reading. An exception occurs if the file does not exist.
|
||||
openOptions = { read: true };
|
||||
break;
|
||||
}
|
||||
case "r+": {
|
||||
// 'r+': Open file for reading and writing. An exception occurs if the file does not exist.
|
||||
openOptions = { read: true, write: true };
|
||||
break;
|
||||
}
|
||||
case "w": {
|
||||
// 'w': Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
|
||||
openOptions = { create: true, write: true, truncate: true };
|
||||
break;
|
||||
}
|
||||
case "wx": {
|
||||
// 'wx': Like 'w' but fails if the path exists.
|
||||
openOptions = { createNew: true, write: true };
|
||||
break;
|
||||
}
|
||||
case "w+": {
|
||||
// 'w+': Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
|
||||
openOptions = { create: true, write: true, truncate: true, read: true };
|
||||
break;
|
||||
}
|
||||
case "wx+": {
|
||||
// 'wx+': Like 'w+' but fails if the path exists.
|
||||
openOptions = { createNew: true, write: true, read: true };
|
||||
break;
|
||||
}
|
||||
case "as": {
|
||||
// 'as': Open file for appending in synchronous mode. The file is created if it does not exist.
|
||||
openOptions = { create: true, append: true };
|
||||
}
|
||||
case "as+": {
|
||||
// 'as+': Open file for reading and appending in synchronous mode. The file is created if it does not exist.
|
||||
openOptions = { create: true, read: true, append: true };
|
||||
}
|
||||
case "rs+": {
|
||||
// 'rs+': Open file for reading and writing in synchronous mode. Instructs the operating system to bypass the local file system cache.
|
||||
openOptions = { create: true, read: true, write: true };
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unrecognized file system flag: ${flag}`);
|
||||
}
|
||||
}
|
||||
|
||||
return openOptions;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ test({
|
|||
fn: async () => {
|
||||
const srouceFile = Deno.makeTempFileSync();
|
||||
const err = await new Promise((resolve) => {
|
||||
copyFile(srouceFile, destFile, (err: Error | undefined) => resolve(err));
|
||||
copyFile(srouceFile, destFile, (err?: Error | null) => resolve(err));
|
||||
});
|
||||
assert(!err);
|
||||
assert(existsSync(destFile));
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import {
|
||||
notImplemented,
|
||||
intoCallbackAPIWithIntercept,
|
||||
MaybeEmpty,
|
||||
} from "../_utils.ts";
|
||||
import { intoCallbackAPIWithIntercept, MaybeEmpty } from "../_utils.ts";
|
||||
|
||||
import { getEncoding, FileOptions } from "./_fs_common.ts";
|
||||
import { fromFileUrl } from "../path.ts";
|
||||
|
||||
const { readFile: denoReadFile, readFileSync: denoReadFileSync } = Deno;
|
||||
|
@ -14,33 +12,6 @@ type ReadFileCallback = (
|
|||
data: MaybeEmpty<string | Uint8Array>
|
||||
) => void;
|
||||
|
||||
interface ReadFileOptions {
|
||||
encoding?: string | null;
|
||||
flag?: string;
|
||||
}
|
||||
|
||||
function getEncoding(
|
||||
optOrCallback?: ReadFileOptions | ReadFileCallback
|
||||
): string | null {
|
||||
if (!optOrCallback || typeof optOrCallback === "function") {
|
||||
return null;
|
||||
} else {
|
||||
if (optOrCallback.encoding) {
|
||||
if (
|
||||
optOrCallback.encoding === "utf8" ||
|
||||
optOrCallback.encoding === "utf-8"
|
||||
) {
|
||||
return "utf8";
|
||||
} else if (optOrCallback.encoding === "buffer") {
|
||||
return "buffer";
|
||||
} else {
|
||||
notImplemented();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function maybeDecode(
|
||||
data: Uint8Array,
|
||||
encoding: string | null
|
||||
|
@ -53,7 +24,7 @@ function maybeDecode(
|
|||
|
||||
export function readFile(
|
||||
path: string | URL,
|
||||
optOrCallback: ReadFileCallback | ReadFileOptions,
|
||||
optOrCallback: ReadFileCallback | FileOptions,
|
||||
callback?: ReadFileCallback
|
||||
): void {
|
||||
path = path instanceof URL ? fromFileUrl(path) : path;
|
||||
|
@ -76,7 +47,7 @@ export function readFile(
|
|||
|
||||
export function readFileSync(
|
||||
path: string | URL,
|
||||
opt?: ReadFileOptions
|
||||
opt?: FileOptions
|
||||
): string | Uint8Array {
|
||||
path = path instanceof URL ? fromFileUrl(path) : path;
|
||||
return maybeDecode(denoReadFileSync(path), getEncoding(opt));
|
||||
|
|
65
std/node/_fs/_fs_writeFile.ts
Normal file
65
std/node/_fs/_fs_writeFile.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { notImplemented } from "../_utils.ts";
|
||||
|
||||
import {
|
||||
WriteFileOptions,
|
||||
CallbackWithError,
|
||||
isFileOptions,
|
||||
getEncoding,
|
||||
getOpenOptions,
|
||||
} from "./_fs_common.ts";
|
||||
|
||||
export function writeFile(
|
||||
pathOrRid: string | number,
|
||||
data: string | Uint8Array,
|
||||
optOrCallback: string | CallbackWithError | WriteFileOptions | undefined,
|
||||
callback?: CallbackWithError
|
||||
): void {
|
||||
const callbackFn: CallbackWithError | undefined =
|
||||
optOrCallback instanceof Function ? optOrCallback : callback;
|
||||
const options: string | WriteFileOptions | undefined =
|
||||
optOrCallback instanceof Function ? undefined : optOrCallback;
|
||||
|
||||
if (!callbackFn) {
|
||||
throw new TypeError("Callback must be a function.");
|
||||
}
|
||||
|
||||
const flag: string | undefined = isFileOptions(options)
|
||||
? options.flag
|
||||
: undefined;
|
||||
|
||||
const mode: number | undefined = isFileOptions(options)
|
||||
? options.mode
|
||||
: undefined;
|
||||
|
||||
const encoding = getEncoding(options) || "utf8";
|
||||
const openOptions = getOpenOptions(flag || "w");
|
||||
|
||||
if (typeof data === "string" && encoding === "utf8")
|
||||
data = new TextEncoder().encode(data) as Uint8Array;
|
||||
|
||||
const isRid = typeof pathOrRid === "number";
|
||||
let file;
|
||||
|
||||
let error: Error | null = null;
|
||||
(async (): Promise<void> => {
|
||||
try {
|
||||
file = isRid
|
||||
? new Deno.File(pathOrRid as number)
|
||||
: await Deno.open(pathOrRid as string, openOptions);
|
||||
|
||||
if (!isRid && mode) {
|
||||
if (Deno.build.os === "windows") notImplemented(`"mode" on Windows`);
|
||||
await Deno.chmod(pathOrRid as string, mode);
|
||||
}
|
||||
|
||||
await Deno.writeAll(file, data as Uint8Array);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
} finally {
|
||||
// Make sure to close resource
|
||||
if (!isRid && file) file.close();
|
||||
callbackFn(error);
|
||||
}
|
||||
})();
|
||||
}
|
180
std/node/_fs/_fs_writeFile_test.ts
Normal file
180
std/node/_fs/_fs_writeFile_test.ts
Normal file
|
@ -0,0 +1,180 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
const { test } = Deno;
|
||||
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
assertNotEquals,
|
||||
assertThrows,
|
||||
assertThrowsAsync,
|
||||
} from "../../testing/asserts.ts";
|
||||
import { writeFile } from "./_fs_writeFile.ts";
|
||||
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
|
||||
test("Invalid encoding results in error()", function fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
writeFile("some/path", "some data", "utf8");
|
||||
},
|
||||
TypeError,
|
||||
"Callback must be a function."
|
||||
);
|
||||
});
|
||||
|
||||
test("Invalid encoding results in error()", function testEncodingErrors() {
|
||||
assertThrows(
|
||||
() => {
|
||||
writeFile("some/path", "some data", "made-up-encoding", () => {});
|
||||
},
|
||||
Error,
|
||||
`The value "made-up-encoding" is invalid for option "encoding"`
|
||||
);
|
||||
assertThrows(
|
||||
() => {
|
||||
writeFile(
|
||||
"some/path",
|
||||
"some data",
|
||||
{
|
||||
encoding: "made-up-encoding",
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
},
|
||||
Error,
|
||||
`The value "made-up-encoding" is invalid for option "encoding"`
|
||||
);
|
||||
});
|
||||
|
||||
test("Unsupported encoding results in error()", function testUnsupportedEncoding() {
|
||||
assertThrows(
|
||||
() => {
|
||||
writeFile("some/path", "some data", "hex", () => {});
|
||||
},
|
||||
Error,
|
||||
`Not implemented: "hex" encoding`
|
||||
);
|
||||
assertThrows(
|
||||
() => {
|
||||
writeFile(
|
||||
"some/path",
|
||||
"some data",
|
||||
{
|
||||
encoding: "base64",
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
},
|
||||
Error,
|
||||
`Not implemented: "base64" encoding`
|
||||
);
|
||||
});
|
||||
|
||||
test("Data is written to correct rid", async function testCorrectWriteUsingRid() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
const file: Deno.File = await Deno.open(tempFile, {
|
||||
create: true,
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
writeFile(file.rid, "hello world", (err) => {
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
Deno.close(file.rid);
|
||||
|
||||
const data = await Deno.readFile(tempFile);
|
||||
await Deno.remove(tempFile);
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
});
|
||||
|
||||
test("Data is written to correct rid", async function testCorrectWriteUsingRid() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
const file: Deno.File = await Deno.open(tempFile, {
|
||||
create: true,
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
writeFile(file.rid, "hello world", (err) => {
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
Deno.close(file.rid);
|
||||
|
||||
const data = await Deno.readFile(tempFile);
|
||||
await Deno.remove(tempFile);
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
});
|
||||
|
||||
test("Data is written to correct file", async function testCorrectWriteUsingPath() {
|
||||
const res = await new Promise((resolve) => {
|
||||
writeFile("_fs_writeFile_test_file.txt", "hello world", resolve);
|
||||
});
|
||||
|
||||
const data = await Deno.readFile("_fs_writeFile_test_file.txt");
|
||||
await Deno.remove("_fs_writeFile_test_file.txt");
|
||||
assertEquals(res, null);
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
});
|
||||
|
||||
test("Mode is correctly set", async function testCorrectFileMode() {
|
||||
if (Deno.build.os === "windows") return;
|
||||
const filename = "_fs_writeFile_test_file.txt";
|
||||
|
||||
const res = await new Promise((resolve) => {
|
||||
writeFile(filename, "hello world", { mode: 0o777 }, resolve);
|
||||
});
|
||||
|
||||
const fileInfo = await Deno.stat(filename);
|
||||
await Deno.remove(filename);
|
||||
assertEquals(res, null);
|
||||
assert(fileInfo && fileInfo.mode);
|
||||
assertEquals(fileInfo.mode & 0o777, 0o777);
|
||||
});
|
||||
|
||||
test("Mode is not set when rid is passed", async function testCorrectFileModeRid() {
|
||||
if (Deno.build.os === "windows") return;
|
||||
|
||||
const filename: string = await Deno.makeTempFile();
|
||||
const file: Deno.File = await Deno.open(filename, {
|
||||
create: true,
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
writeFile(file.rid, "hello world", { mode: 0o777 }, (err) => {
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
Deno.close(file.rid);
|
||||
|
||||
const fileInfo = await Deno.stat(filename);
|
||||
await Deno.remove(filename);
|
||||
assert(fileInfo.mode);
|
||||
assertNotEquals(fileInfo.mode & 0o777, 0o777);
|
||||
});
|
||||
|
||||
test("Mode is not implemented on windows", function testModeNotImplementedWindows(): void {
|
||||
if (Deno.build.os !== "windows") return;
|
||||
|
||||
assertThrowsAsync(
|
||||
() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
writeFile("fail.txt", "some data", { mode: 0o777 }, (err) => {
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
Error,
|
||||
`Not implemented: "mode" on Windows`
|
||||
);
|
||||
});
|
17
std/node/_fs/promises/_fs_writeFile.ts
Normal file
17
std/node/_fs/promises/_fs_writeFile.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { WriteFileOptions } from "../_fs_common.ts";
|
||||
|
||||
import { writeFile as writeFileCallback } from "../_fs_writeFile.ts";
|
||||
|
||||
export function writeFile(
|
||||
pathOrRid: string | number,
|
||||
data: string | Uint8Array,
|
||||
options?: string | WriteFileOptions
|
||||
): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
writeFileCallback(pathOrRid, data, options, (err?: Error | null) => {
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
119
std/node/_fs/promises/_fs_writeFile_test.ts
Normal file
119
std/node/_fs/promises/_fs_writeFile_test.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
const { test } = Deno;
|
||||
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
assertNotEquals,
|
||||
assertThrowsAsync,
|
||||
} from "../../../testing/asserts.ts";
|
||||
import { writeFile } from "./_fs_writeFile.ts";
|
||||
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
|
||||
test("Invalid encoding results in error()", function testEncodingErrors() {
|
||||
assertThrowsAsync(
|
||||
async () => {
|
||||
await writeFile("some/path", "some data", "made-up-encoding");
|
||||
},
|
||||
Error,
|
||||
`The value "made-up-encoding" is invalid for option "encoding"`
|
||||
);
|
||||
assertThrowsAsync(
|
||||
async () => {
|
||||
await writeFile("some/path", "some data", {
|
||||
encoding: "made-up-encoding",
|
||||
});
|
||||
},
|
||||
Error,
|
||||
`The value "made-up-encoding" is invalid for option "encoding"`
|
||||
);
|
||||
});
|
||||
|
||||
test("Unsupported encoding results in error()", function testUnsupportedEncoding() {
|
||||
assertThrowsAsync(
|
||||
async () => {
|
||||
await writeFile("some/path", "some data", "hex");
|
||||
},
|
||||
Error,
|
||||
`Not implemented: "hex" encoding`
|
||||
);
|
||||
assertThrowsAsync(
|
||||
async () => {
|
||||
await writeFile("some/path", "some data", {
|
||||
encoding: "base64",
|
||||
});
|
||||
},
|
||||
Error,
|
||||
`Not implemented: "base64" encoding`
|
||||
);
|
||||
});
|
||||
|
||||
test("Data is written to correct rid", async function testCorrectWriteUsingRid() {
|
||||
const tempFile: string = await Deno.makeTempFile();
|
||||
const file: Deno.File = await Deno.open(tempFile, {
|
||||
create: true,
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
|
||||
await writeFile(file.rid, "hello world");
|
||||
Deno.close(file.rid);
|
||||
|
||||
const data = await Deno.readFile(tempFile);
|
||||
await Deno.remove(tempFile);
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
});
|
||||
|
||||
test("Data is written to correct file", async function testCorrectWriteUsingPath() {
|
||||
const openResourcesBeforeWrite: Deno.ResourceMap = Deno.resources();
|
||||
|
||||
await writeFile("_fs_writeFile_test_file.txt", "hello world");
|
||||
|
||||
assertEquals(Deno.resources(), openResourcesBeforeWrite);
|
||||
const data = await Deno.readFile("_fs_writeFile_test_file.txt");
|
||||
await Deno.remove("_fs_writeFile_test_file.txt");
|
||||
assertEquals(decoder.decode(data), "hello world");
|
||||
});
|
||||
|
||||
test("Mode is correctly set", async function testCorrectFileMode() {
|
||||
if (Deno.build.os === "windows") return;
|
||||
const filename = "_fs_writeFile_test_file.txt";
|
||||
await writeFile(filename, "hello world", { mode: 0o777 });
|
||||
|
||||
const fileInfo = await Deno.stat(filename);
|
||||
await Deno.remove(filename);
|
||||
assert(fileInfo && fileInfo.mode);
|
||||
assertEquals(fileInfo.mode & 0o777, 0o777);
|
||||
});
|
||||
|
||||
test("Mode is not set when rid is passed", async function testCorrectFileModeRid() {
|
||||
if (Deno.build.os === "windows") return;
|
||||
|
||||
const filename: string = await Deno.makeTempFile();
|
||||
const file: Deno.File = await Deno.open(filename, {
|
||||
create: true,
|
||||
write: true,
|
||||
read: true,
|
||||
});
|
||||
|
||||
await writeFile(file.rid, "hello world", { mode: 0o777 });
|
||||
Deno.close(file.rid);
|
||||
|
||||
const fileInfo = await Deno.stat(filename);
|
||||
await Deno.remove(filename);
|
||||
assert(fileInfo.mode);
|
||||
assertNotEquals(fileInfo.mode & 0o777, 0o777);
|
||||
});
|
||||
|
||||
test("Mode is not implemented on windows", function testModeNotImplementedWindows(): void {
|
||||
if (Deno.build.os !== "windows") return;
|
||||
|
||||
assertThrowsAsync(
|
||||
async () => {
|
||||
await writeFile("fail.txt", "some data", { mode: 0o777 });
|
||||
},
|
||||
Error,
|
||||
`Not implemented: "mode" on Windows`
|
||||
);
|
||||
});
|
1
std/node/_fs/promises/mod.ts
Normal file
1
std/node/_fs/promises/mod.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { writeFile } from "./_fs_writeFile.ts";
|
|
@ -11,6 +11,8 @@ import { readlink, readlinkSync } from "./_fs/_fs_readlink.ts";
|
|||
import { exists, existsSync } from "./_fs/_fs_exists.ts";
|
||||
import { mkdir, mkdirSync } from "./_fs/_fs_mkdir.ts";
|
||||
import { copyFile, copyFileSync } from "./_fs/_fs_copy.ts";
|
||||
import { writeFile } from "./_fs/_fs_writeFile.ts";
|
||||
import * as promises from "./_fs/promises/mod.ts";
|
||||
|
||||
export {
|
||||
access,
|
||||
|
@ -34,4 +36,6 @@ export {
|
|||
readlinkSync,
|
||||
mkdir,
|
||||
mkdirSync,
|
||||
writeFile,
|
||||
promises,
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue