mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
549 lines
16 KiB
TypeScript
549 lines
16 KiB
TypeScript
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
import { assert, assertEquals, assertRejects, assertThrows } from "@std/assert";
|
|
import * as path from "@std/path";
|
|
import { copy, copySync } from "./copy.ts";
|
|
import { existsSync } from "./exists.ts";
|
|
import { ensureDir, ensureDirSync } from "./ensure_dir.ts";
|
|
import { ensureFile, ensureFileSync } from "./ensure_file.ts";
|
|
import { ensureSymlink, ensureSymlinkSync } from "./ensure_symlink.ts";
|
|
|
|
const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
|
|
const testdataDir = path.resolve(moduleDir, "testdata");
|
|
|
|
function testCopy(
|
|
name: string,
|
|
cb: (tempDir: string) => Promise<void>,
|
|
ignore = false,
|
|
) {
|
|
Deno.test({
|
|
name,
|
|
async fn() {
|
|
const tempDir = await Deno.makeTempDir({
|
|
prefix: "deno_std_copy_async_test_",
|
|
});
|
|
await cb(tempDir);
|
|
await Deno.remove(tempDir, { recursive: true });
|
|
},
|
|
ignore,
|
|
});
|
|
}
|
|
|
|
function testCopySync(name: string, cb: (tempDir: string) => void) {
|
|
Deno.test({
|
|
name,
|
|
fn: () => {
|
|
const tempDir = Deno.makeTempDirSync({
|
|
prefix: "deno_std_copy_sync_test_",
|
|
});
|
|
cb(tempDir);
|
|
Deno.removeSync(tempDir, { recursive: true });
|
|
},
|
|
});
|
|
}
|
|
|
|
testCopy(
|
|
"copy() rejects if src does not exist",
|
|
async (tempDir: string) => {
|
|
const srcFile = path.join(testdataDir, "copy_file_not_exists.txt");
|
|
const destFile = path.join(tempDir, "copy_file_not_exists_1.txt");
|
|
await assertRejects(
|
|
async () => {
|
|
await copy(srcFile, destFile);
|
|
},
|
|
);
|
|
},
|
|
);
|
|
|
|
testCopy(
|
|
"copy() rejects if src and dest are the same paths",
|
|
async (tempDir: string) => {
|
|
const srcFile = path.join(tempDir, "copy_file_same.txt");
|
|
const destFile = path.join(tempDir, "copy_file_same.txt");
|
|
await assertRejects(
|
|
async () => {
|
|
await copy(srcFile, destFile);
|
|
},
|
|
Error,
|
|
"Source and destination cannot be the same",
|
|
);
|
|
},
|
|
);
|
|
|
|
testCopy(
|
|
"copy() copies file to new destination",
|
|
async (tempDir: string) => {
|
|
const srcFile = path.join(testdataDir, "copy_file.txt");
|
|
const destFile = path.join(tempDir, "copy_file_copy.txt");
|
|
|
|
const srcContent = await Deno.readTextFile(srcFile);
|
|
|
|
assert(await Deno.lstat(srcFile), "source should exist before copy");
|
|
await assertRejects(
|
|
async () => await Deno.lstat(destFile),
|
|
"destination should not exist before copy",
|
|
);
|
|
|
|
await copy(srcFile, destFile);
|
|
|
|
assert(await Deno.lstat(srcFile), "source should exist after copy");
|
|
assert(await Deno.lstat(destFile), "destination should exist after copy");
|
|
|
|
const destContent = await Deno.readTextFile(destFile);
|
|
|
|
assertEquals(
|
|
srcContent,
|
|
destContent,
|
|
"source and destination should have the same content",
|
|
);
|
|
|
|
// Copy again and it should throw an error.
|
|
await assertRejects(
|
|
async () => {
|
|
await copy(srcFile, destFile);
|
|
},
|
|
Error,
|
|
`'${destFile}' already exists`,
|
|
);
|
|
|
|
// Modify destination file.
|
|
|
|
await Deno.writeTextFile(destFile, "txt copy");
|
|
|
|
assertEquals(await Deno.readTextFile(destFile), "txt copy");
|
|
|
|
// Copy again with overwrite option.
|
|
await copy(srcFile, destFile, { overwrite: true });
|
|
|
|
// Make sure the file has been overwritten.
|
|
assertEquals(await Deno.readTextFile(destFile), "txt");
|
|
},
|
|
);
|
|
|
|
testCopy(
|
|
"copy() copies with preserve timestamps",
|
|
async (tempDir: string) => {
|
|
{
|
|
const srcFile = path.join(testdataDir, "copy_file.txt");
|
|
const destFile = path.join(tempDir, "copy_file_copy.txt");
|
|
|
|
const srcStatInfo = await Deno.stat(srcFile);
|
|
|
|
assert(srcStatInfo.atime instanceof Date);
|
|
assert(srcStatInfo.mtime instanceof Date);
|
|
|
|
// Copy with overwrite and preserve timestamps options.
|
|
await copy(srcFile, destFile, {
|
|
overwrite: true,
|
|
preserveTimestamps: true,
|
|
});
|
|
|
|
const destStatInfo = await Deno.stat(destFile);
|
|
|
|
assert(destStatInfo.atime instanceof Date);
|
|
assert(destStatInfo.mtime instanceof Date);
|
|
assertEquals(destStatInfo.atime, srcStatInfo.atime);
|
|
assertEquals(destStatInfo.mtime, srcStatInfo.mtime);
|
|
}
|
|
|
|
// copy dir with preserve timestamps
|
|
{
|
|
const srcDir = path.join(testdataDir, "copy_dir");
|
|
const destDir = path.join(tempDir, "copy_dir");
|
|
const srcFile = path.join(srcDir, "0.txt");
|
|
const destFile = path.join(destDir, "0.txt");
|
|
const srcNestFile = path.join(srcDir, "nest", "0.txt");
|
|
const destNestFile = path.join(destDir, "nest", "0.txt");
|
|
|
|
await copy(srcDir, destDir, { preserveTimestamps: true });
|
|
|
|
const srcDirInfo = await Deno.stat(srcFile);
|
|
const destDirInfo = await Deno.stat(destFile);
|
|
const srcFileInfo = await Deno.stat(srcFile);
|
|
const destFileInfo = await Deno.stat(destFile);
|
|
const srcNestFileInfo = await Deno.stat(srcNestFile);
|
|
const destNestFileInfo = await Deno.stat(destNestFile);
|
|
|
|
assertEquals(srcDirInfo.atime, destDirInfo.atime);
|
|
assertEquals(srcDirInfo.mtime, destDirInfo.mtime);
|
|
assertEquals(srcFileInfo.atime, destFileInfo.atime);
|
|
assertEquals(srcFileInfo.mtime, destFileInfo.mtime);
|
|
assertEquals(srcNestFileInfo.atime, destNestFileInfo.atime);
|
|
assertEquals(srcNestFileInfo.mtime, destNestFileInfo.mtime);
|
|
}
|
|
},
|
|
);
|
|
|
|
testCopy(
|
|
"copy() rejects if destination is its own subdirectory",
|
|
async (tempDir: string) => {
|
|
const srcDir = path.join(tempDir, "parent");
|
|
const destDir = path.join(srcDir, "child");
|
|
|
|
await ensureDir(srcDir);
|
|
|
|
await assertRejects(
|
|
async () => {
|
|
await copy(srcDir, destDir);
|
|
},
|
|
Error,
|
|
`Cannot copy '${srcDir}' to a subdirectory of itself: '${destDir}'`,
|
|
);
|
|
},
|
|
);
|
|
|
|
testCopy(
|
|
"copy() rejects when copying a directory to an existent destination that is not a directory",
|
|
async (tempDir: string) => {
|
|
const srcDir = path.join(tempDir, "parent");
|
|
const destDir = path.join(tempDir, "child.txt");
|
|
|
|
await ensureDir(srcDir);
|
|
await ensureFile(destDir);
|
|
|
|
await assertRejects(
|
|
async () => {
|
|
await copy(srcDir, destDir);
|
|
},
|
|
Error,
|
|
`Cannot overwrite non-directory '${destDir}' with directory '${srcDir}'`,
|
|
);
|
|
},
|
|
);
|
|
|
|
testCopy(
|
|
"copy() copies a directory",
|
|
async (tempDir: string) => {
|
|
const srcDir = path.join(testdataDir, "copy_dir");
|
|
const destDir = path.join(tempDir, "copy_dir");
|
|
const srcFile = path.join(srcDir, "0.txt");
|
|
const destFile = path.join(destDir, "0.txt");
|
|
const srcNestFile = path.join(srcDir, "nest", "0.txt");
|
|
const destNestFile = path.join(destDir, "nest", "0.txt");
|
|
|
|
await copy(srcDir, destDir);
|
|
|
|
assert(await Deno.lstat(destFile));
|
|
assert(await Deno.lstat(destNestFile));
|
|
|
|
// After copy. The source and destination should have the same content.
|
|
assertEquals(
|
|
await Deno.readTextFile(srcFile),
|
|
await Deno.readTextFile(destFile),
|
|
);
|
|
assertEquals(
|
|
await Deno.readTextFile(srcNestFile),
|
|
await Deno.readTextFile(destNestFile),
|
|
);
|
|
|
|
// Copy again without overwrite option and it should throw an error.
|
|
await assertRejects(
|
|
async () => {
|
|
await copy(srcDir, destDir);
|
|
},
|
|
Error,
|
|
`'${destDir}' already exists`,
|
|
);
|
|
|
|
// Modify the file in the destination directory.
|
|
await Deno.writeTextFile(destNestFile, "nest copy");
|
|
assertEquals(await Deno.readTextFile(destNestFile), "nest copy");
|
|
|
|
// Copy again with overwrite option.
|
|
await copy(srcDir, destDir, { overwrite: true });
|
|
|
|
// Make sure the file has been overwritten.
|
|
assertEquals(await Deno.readTextFile(destNestFile), "nest");
|
|
},
|
|
);
|
|
|
|
testCopy(
|
|
"copy() copies a symlink file",
|
|
async (tempDir: string) => {
|
|
const dir = path.join(testdataDir, "copy_dir_link_file");
|
|
const srcLink = path.join(dir, "0.txt");
|
|
const destLink = path.join(tempDir, "0_copy.txt");
|
|
|
|
assert(
|
|
(await Deno.lstat(srcLink)).isSymlink,
|
|
`'${srcLink}' should be symlink type`,
|
|
);
|
|
|
|
await copy(srcLink, destLink);
|
|
|
|
const statInfo = await Deno.lstat(destLink);
|
|
|
|
assert(statInfo.isSymlink, `'${destLink}' should be symlink type`);
|
|
},
|
|
);
|
|
|
|
testCopy(
|
|
"copy() copies a symlink directory",
|
|
async (tempDir: string) => {
|
|
const srcDir = path.join(testdataDir, "copy_dir");
|
|
const srcLink = path.join(tempDir, "copy_dir_link");
|
|
const destLink = path.join(tempDir, "copy_dir_link_copy");
|
|
|
|
await ensureSymlink(srcDir, srcLink);
|
|
|
|
assert(
|
|
(await Deno.lstat(srcLink)).isSymlink,
|
|
`'${srcLink}' should be symlink type`,
|
|
);
|
|
|
|
await copy(srcLink, destLink);
|
|
|
|
const statInfo = await Deno.lstat(destLink);
|
|
|
|
assert(statInfo.isSymlink);
|
|
},
|
|
);
|
|
|
|
testCopySync(
|
|
"copySync() throws if src does not exist",
|
|
(tempDir: string) => {
|
|
const srcFile = path.join(testdataDir, "copy_file_not_exists_sync.txt");
|
|
const destFile = path.join(tempDir, "copy_file_not_exists_1_sync.txt");
|
|
assertThrows(() => {
|
|
copySync(srcFile, destFile);
|
|
});
|
|
},
|
|
);
|
|
|
|
testCopySync(
|
|
"copySync() copies with preserve timestamps",
|
|
(tempDir: string) => {
|
|
{
|
|
const srcFile = path.join(testdataDir, "copy_file.txt");
|
|
const destFile = path.join(tempDir, "copy_file_copy.txt");
|
|
|
|
const srcStatInfo = Deno.statSync(srcFile);
|
|
|
|
assert(srcStatInfo.atime instanceof Date);
|
|
assert(srcStatInfo.mtime instanceof Date);
|
|
|
|
// Copy with overwrite and preserve timestamps options.
|
|
copySync(srcFile, destFile, {
|
|
overwrite: true,
|
|
preserveTimestamps: true,
|
|
});
|
|
|
|
const destStatInfo = Deno.statSync(destFile);
|
|
|
|
assert(destStatInfo.atime instanceof Date);
|
|
assert(destStatInfo.mtime instanceof Date);
|
|
assertEquals(destStatInfo.atime, srcStatInfo.atime);
|
|
assertEquals(destStatInfo.mtime, srcStatInfo.mtime);
|
|
}
|
|
|
|
// copy dir with preserve timestamps
|
|
{
|
|
const srcDir = path.join(testdataDir, "copy_dir");
|
|
const destDir = path.join(tempDir, "copy_dir");
|
|
const srcFile = path.join(srcDir, "0.txt");
|
|
const destFile = path.join(destDir, "0.txt");
|
|
const srcNestFile = path.join(srcDir, "nest", "0.txt");
|
|
const destNestFile = path.join(destDir, "nest", "0.txt");
|
|
|
|
copySync(srcDir, destDir, { preserveTimestamps: true });
|
|
|
|
const srcDirInfo = Deno.statSync(srcFile);
|
|
const destDirInfo = Deno.statSync(destFile);
|
|
const srcFileInfo = Deno.statSync(srcFile);
|
|
const destFileInfo = Deno.statSync(destFile);
|
|
const srcNestFileInfo = Deno.statSync(srcNestFile);
|
|
const destNestFileInfo = Deno.statSync(destNestFile);
|
|
|
|
assertEquals(srcDirInfo.atime, destDirInfo.atime);
|
|
assertEquals(srcDirInfo.mtime, destDirInfo.mtime);
|
|
assertEquals(srcFileInfo.atime, destFileInfo.atime);
|
|
assertEquals(srcFileInfo.mtime, destFileInfo.mtime);
|
|
assertEquals(srcNestFileInfo.atime, destNestFileInfo.atime);
|
|
assertEquals(srcNestFileInfo.mtime, destNestFileInfo.mtime);
|
|
}
|
|
},
|
|
);
|
|
|
|
testCopySync(
|
|
"copySync() throws if src and dest are the same paths",
|
|
() => {
|
|
const srcFile = path.join(testdataDir, "copy_file_same_sync.txt");
|
|
assertThrows(
|
|
() => {
|
|
copySync(srcFile, srcFile);
|
|
},
|
|
Error,
|
|
"Source and destination cannot be the same",
|
|
);
|
|
},
|
|
);
|
|
|
|
testCopySync("copySync() copies file to new destination", (tempDir: string) => {
|
|
const srcFile = path.join(testdataDir, "copy_file.txt");
|
|
const destFile = path.join(tempDir, "copy_file_copy_sync.txt");
|
|
|
|
const srcContent = new TextDecoder().decode(Deno.readFileSync(srcFile));
|
|
|
|
assertEquals(existsSync(srcFile), true);
|
|
assertEquals(existsSync(destFile), false);
|
|
|
|
copySync(srcFile, destFile);
|
|
|
|
assertEquals(existsSync(srcFile), true);
|
|
assertEquals(existsSync(destFile), true);
|
|
|
|
const destContent = new TextDecoder().decode(Deno.readFileSync(destFile));
|
|
|
|
assertEquals(srcContent, destContent);
|
|
|
|
// Copy again without overwrite option and it should throw an error.
|
|
assertThrows(
|
|
() => {
|
|
copySync(srcFile, destFile);
|
|
},
|
|
Error,
|
|
`'${destFile}' already exists`,
|
|
);
|
|
|
|
// Modify destination file.
|
|
Deno.writeFileSync(destFile, new TextEncoder().encode("txt copy"));
|
|
|
|
assertEquals(
|
|
new TextDecoder().decode(Deno.readFileSync(destFile)),
|
|
"txt copy",
|
|
);
|
|
|
|
// Copy again with overwrite option.
|
|
copySync(srcFile, destFile, { overwrite: true });
|
|
|
|
// Make sure the file has been overwritten.
|
|
assertEquals(new TextDecoder().decode(Deno.readFileSync(destFile)), "txt");
|
|
});
|
|
|
|
testCopySync(
|
|
"copySync() throws if destination is its own subdirectory",
|
|
(tempDir: string) => {
|
|
const srcDir = path.join(tempDir, "parent");
|
|
const destDir = path.join(srcDir, "child");
|
|
|
|
ensureDirSync(srcDir);
|
|
|
|
assertThrows(
|
|
() => {
|
|
copySync(srcDir, destDir);
|
|
},
|
|
Error,
|
|
`Cannot copy '${srcDir}' to a subdirectory of itself: '${destDir}'`,
|
|
);
|
|
},
|
|
);
|
|
|
|
testCopySync(
|
|
"copySync() throws when copying a directory to an existent destination that is not a directory",
|
|
(tempDir: string) => {
|
|
const srcDir = path.join(tempDir, "parent_sync");
|
|
const destDir = path.join(tempDir, "child.txt");
|
|
|
|
ensureDirSync(srcDir);
|
|
ensureFileSync(destDir);
|
|
|
|
assertThrows(
|
|
() => {
|
|
copySync(srcDir, destDir);
|
|
},
|
|
Error,
|
|
`Cannot overwrite non-directory '${destDir}' with directory '${srcDir}'`,
|
|
);
|
|
},
|
|
);
|
|
|
|
testCopySync("copySync() copies a directory", (tempDir: string) => {
|
|
const srcDir = path.join(testdataDir, "copy_dir");
|
|
const destDir = path.join(tempDir, "copy_dir_copy_sync");
|
|
const srcFile = path.join(srcDir, "0.txt");
|
|
const destFile = path.join(destDir, "0.txt");
|
|
const srcNestFile = path.join(srcDir, "nest", "0.txt");
|
|
const destNestFile = path.join(destDir, "nest", "0.txt");
|
|
|
|
copySync(srcDir, destDir);
|
|
|
|
assertEquals(existsSync(destFile), true);
|
|
assertEquals(existsSync(destNestFile), true);
|
|
|
|
// After copy. The source and destination should have the same content.
|
|
assertEquals(
|
|
new TextDecoder().decode(Deno.readFileSync(srcFile)),
|
|
new TextDecoder().decode(Deno.readFileSync(destFile)),
|
|
);
|
|
assertEquals(
|
|
new TextDecoder().decode(Deno.readFileSync(srcNestFile)),
|
|
new TextDecoder().decode(Deno.readFileSync(destNestFile)),
|
|
);
|
|
|
|
// Copy again without overwrite option and it should throw an error.
|
|
assertThrows(
|
|
() => {
|
|
copySync(srcDir, destDir);
|
|
},
|
|
Error,
|
|
`'${destDir}' already exists`,
|
|
);
|
|
|
|
// Modify the file in the destination directory.
|
|
Deno.writeFileSync(destNestFile, new TextEncoder().encode("nest copy"));
|
|
assertEquals(
|
|
new TextDecoder().decode(Deno.readFileSync(destNestFile)),
|
|
"nest copy",
|
|
);
|
|
|
|
// Copy again with overwrite option.
|
|
copySync(srcDir, destDir, { overwrite: true });
|
|
|
|
// Make sure the file has been overwritten.
|
|
assertEquals(
|
|
new TextDecoder().decode(Deno.readFileSync(destNestFile)),
|
|
"nest",
|
|
);
|
|
});
|
|
|
|
testCopySync(
|
|
"copySync() copies symlink file",
|
|
(tempDir: string) => {
|
|
const dir = path.join(testdataDir, "copy_dir_link_file");
|
|
const srcLink = path.join(dir, "0.txt");
|
|
const destLink = path.join(tempDir, "0_copy.txt");
|
|
|
|
assert(
|
|
Deno.lstatSync(srcLink).isSymlink,
|
|
`'${srcLink}' should be symlink type`,
|
|
);
|
|
|
|
copySync(srcLink, destLink);
|
|
|
|
const statInfo = Deno.lstatSync(destLink);
|
|
|
|
assert(statInfo.isSymlink, `'${destLink}' should be symlink type`);
|
|
},
|
|
);
|
|
|
|
testCopySync(
|
|
"copySync() copies symlink directory",
|
|
(tempDir: string) => {
|
|
const originDir = path.join(testdataDir, "copy_dir");
|
|
const srcLink = path.join(tempDir, "copy_dir_link");
|
|
const destLink = path.join(tempDir, "copy_dir_link_copy");
|
|
|
|
ensureSymlinkSync(originDir, srcLink);
|
|
|
|
assert(
|
|
Deno.lstatSync(srcLink).isSymlink,
|
|
`'${srcLink}' should be symlink type`,
|
|
);
|
|
|
|
copySync(srcLink, destLink);
|
|
|
|
const statInfo = Deno.lstatSync(destLink);
|
|
|
|
assert(statInfo.isSymlink);
|
|
},
|
|
);
|