| import fs from "node:fs/promises"; |
| import path from "node:path"; |
| import { vi } from "vitest"; |
|
|
| export async function createRebindableDirectoryAlias(params: { |
| aliasPath: string; |
| targetPath: string; |
| }): Promise<void> { |
| const aliasPath = path.resolve(params.aliasPath); |
| const targetPath = path.resolve(params.targetPath); |
| await fs.rm(aliasPath, { recursive: true, force: true }); |
| await fs.symlink(targetPath, aliasPath, process.platform === "win32" ? "junction" : undefined); |
| } |
|
|
| export async function withRealpathSymlinkRebindRace<T>(params: { |
| shouldFlip: (realpathInput: string) => boolean; |
| symlinkPath: string; |
| symlinkTarget: string; |
| timing?: "before-realpath" | "after-realpath"; |
| run: () => Promise<T>; |
| }): Promise<T> { |
| const realRealpath = fs.realpath.bind(fs); |
| let flipped = false; |
| const realpathSpy = vi |
| .spyOn(fs, "realpath") |
| .mockImplementation(async (...args: Parameters<typeof fs.realpath>) => { |
| const filePath = String(args[0]); |
| if (!flipped && params.shouldFlip(filePath)) { |
| flipped = true; |
| if (params.timing !== "after-realpath") { |
| await createRebindableDirectoryAlias({ |
| aliasPath: params.symlinkPath, |
| targetPath: params.symlinkTarget, |
| }); |
| return await realRealpath(...args); |
| } |
| const resolved = await realRealpath(...args); |
| await createRebindableDirectoryAlias({ |
| aliasPath: params.symlinkPath, |
| targetPath: params.symlinkTarget, |
| }); |
| return resolved; |
| } |
| return await realRealpath(...args); |
| }); |
| try { |
| return await params.run(); |
| } finally { |
| realpathSpy.mockRestore(); |
| } |
| } |
|
|