|
1 |
| -import { describe, test, expect, vi, beforeEach } from "vitest"; |
2 |
| -import * as fs from "node:fs/promises"; |
| 1 | +/* eslint-disable @typescript-eslint/consistent-type-imports */ |
| 2 | +/* eslint-disable @typescript-eslint/no-explicit-any */ |
| 3 | +import { describe, expect, it, vi } from "vitest"; |
3 | 4 | import { createSymlink } from "./symlink";
|
4 |
| -import * as path from "node:path"; |
5 |
| -import type { FileHandle } from "node:fs/promises"; |
6 |
| - |
7 |
| -vi.mock("node:fs/promises", () => ({ |
8 |
| - rm: vi.fn(), |
9 |
| - symlink: vi.fn(), |
10 |
| - rename: vi.fn(), |
11 |
| - copyFile: vi.fn(), |
12 |
| - mkdir: vi.fn(), |
13 |
| - mkdtemp: vi.fn(), |
14 |
| - open: vi.fn(), |
15 |
| -})); |
| 5 | +import { readFileSync, writeFileSync } from "node:fs"; |
| 6 | +import { lstat, rm } from "node:fs/promises"; |
| 7 | +import { tmpdir } from "node:os"; |
| 8 | +import { join } from "node:path"; |
| 9 | + |
| 10 | +let failSymlink = false; |
| 11 | +vi.mock("node:fs/promises", async (importOriginal) => ({ |
| 12 | + ...(await importOriginal<typeof import("node:fs/promises")>()), |
| 13 | + symlink: async (...args: any[]) => { |
| 14 | + if (failSymlink) { |
| 15 | + failSymlink = false; |
| 16 | + throw new Error("Symlink not supported"); |
| 17 | + } |
16 | 18 |
|
17 |
| -vi.mock("node:os", () => ({ |
18 |
| - platform: vi.fn(), |
| 19 | + // @ts-expect-error - ignore |
| 20 | + return (await importOriginal<typeof import("node:fs/promises")>()).symlink(...args); |
| 21 | + }, |
19 | 22 | }));
|
20 | 23 |
|
21 |
| -describe("createSymlink", () => { |
22 |
| - const src = "/path/to/src"; |
23 |
| - const dst = "/path/to/dst"; |
| 24 | +describe("utils/symlink", () => { |
| 25 | + it("should create a symlink", async () => { |
| 26 | + writeFileSync(join(tmpdir(), "test.txt"), "hello world"); |
| 27 | + await createSymlink({ |
| 28 | + sourcePath: join(tmpdir(), "test.txt"), |
| 29 | + finalPath: join(tmpdir(), "test-symlink.txt"), |
| 30 | + }); |
24 | 31 |
|
25 |
| - beforeEach(() => { |
26 |
| - vi.resetAllMocks(); |
27 |
| - vi.mocked(fs.mkdtemp).mockImplementation(async (prefix) => `${prefix}/temp`); |
28 |
| - vi.mocked(fs.open).mockResolvedValue({ close: vi.fn() } as unknown as FileHandle); |
29 |
| - }); |
| 32 | + const stats = await lstat(join(tmpdir(), "test-symlink.txt")); |
| 33 | + expect(stats.isSymbolicLink()).toBe(process.platform !== "win32"); |
30 | 34 |
|
31 |
| - test("should remove existing destination", async () => { |
32 |
| - await createSymlink(dst, src); |
33 |
| - expect(fs.rm).toHaveBeenCalledWith(dst); |
| 35 | + // Test file content |
| 36 | + const content = readFileSync(join(tmpdir(), "test-symlink.txt"), "utf8"); |
| 37 | + expect(content).toBe("hello world"); |
| 38 | + |
| 39 | + // Cleanup |
| 40 | + await rm(join(tmpdir(), "test-symlink.txt")); |
| 41 | + await rm(join(tmpdir(), "test.txt")); |
34 | 42 | });
|
35 | 43 |
|
36 |
| - describe("symlink not supported (Windows)", () => { |
37 |
| - beforeEach(() => { |
38 |
| - vi.mocked(fs.symlink).mockRejectedValue(new Error("Symlink not supported")); |
| 44 | + it("should work when symlinking twice", async () => { |
| 45 | + writeFileSync(join(tmpdir(), "test.txt"), "hello world"); |
| 46 | + writeFileSync(join(tmpdir(), "test2.txt"), "hello world2"); |
| 47 | + await createSymlink({ |
| 48 | + sourcePath: join(tmpdir(), "test.txt"), |
| 49 | + finalPath: join(tmpdir(), "test-symlink.txt"), |
39 | 50 | });
|
40 |
| - |
41 |
| - test("should copyfile", async () => { |
42 |
| - await createSymlink(dst, src); |
43 |
| - expect(fs.copyFile).toHaveBeenCalledWith(path.resolve(dst), path.resolve(src)); |
| 51 | + await createSymlink({ |
| 52 | + sourcePath: join(tmpdir(), "test2.txt"), |
| 53 | + finalPath: join(tmpdir(), "test-symlink.txt"), |
44 | 54 | });
|
45 | 55 |
|
46 |
| - test("should rename file if new_blob is true", async () => { |
47 |
| - await createSymlink(dst, src, true); |
48 |
| - expect(fs.rename).toHaveBeenCalledWith(path.resolve(dst), path.resolve(src)); |
49 |
| - }); |
| 56 | + const stats = await lstat(join(tmpdir(), "test-symlink.txt")); |
| 57 | + expect(stats.isSymbolicLink()).toBe(process.platform !== "win32"); |
| 58 | + |
| 59 | + // Test file content |
| 60 | + const content = readFileSync(join(tmpdir(), "test-symlink.txt"), "utf8"); |
| 61 | + expect(content).toBe("hello world2"); |
| 62 | + |
| 63 | + // Cleanup |
| 64 | + await rm(join(tmpdir(), "test-symlink.txt")); |
| 65 | + await rm(join(tmpdir(), "test.txt")); |
| 66 | + await rm(join(tmpdir(), "test2.txt")); |
50 | 67 | });
|
51 | 68 |
|
52 |
| - describe("symlink supported", () => { |
53 |
| - test("should symlink", async () => { |
54 |
| - await createSymlink(dst, src); |
55 |
| - expect(fs.symlink).toHaveBeenCalledWith(path.resolve(dst), path.resolve(src)); |
56 |
| - }); |
| 69 | + it("should work when symlink doesn't work (windows)", async () => { |
| 70 | + writeFileSync(join(tmpdir(), "test.txt"), "hello world"); |
57 | 71 |
|
58 |
| - test("should symlink if new_blob is true", async () => { |
59 |
| - await createSymlink(dst, src, true); |
60 |
| - expect(fs.symlink).toHaveBeenCalledWith(path.resolve(dst), path.resolve(src)); |
| 72 | + failSymlink = true; |
| 73 | + await createSymlink({ |
| 74 | + sourcePath: join(tmpdir(), "test.txt"), |
| 75 | + finalPath: join(tmpdir(), "test-symlink.txt"), |
61 | 76 | });
|
| 77 | + |
| 78 | + const stats = await lstat(join(tmpdir(), "test-symlink.txt")); |
| 79 | + expect(stats.isSymbolicLink()).toBe(false); |
| 80 | + |
| 81 | + // Test file content |
| 82 | + const content = readFileSync(join(tmpdir(), "test-symlink.txt"), "utf8"); |
| 83 | + expect(content).toBe("hello world"); |
| 84 | + |
| 85 | + // Cleanup |
| 86 | + await rm(join(tmpdir(), "test-symlink.txt")); |
| 87 | + await rm(join(tmpdir(), "test.txt")); |
62 | 88 | });
|
63 | 89 | });
|
0 commit comments