Skip to content

Commit 33f75dd

Browse files
ndycodecodex
andcommitted
test: cover realpath fallback branches in worktree identity
Add deterministic resolveProjectStorageIdentityRoot regressions for canonical path fallback when realpathSync.native throws and when native is unavailable and realpathSync throws. Co-authored-by: Codex <noreply@openai.com>
1 parent 05120d3 commit 33f75dd

1 file changed

Lines changed: 138 additions & 0 deletions

File tree

test/paths.test.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,144 @@ describe("Storage Paths Module", () => {
440440
expect(normalize(resolved)).toBe(normalize(sharedRepoRoot));
441441
});
442442

443+
it("falls back to normalized paths when realpathSync.native throws", () => {
444+
const projectRoot = path.win32.join("X:\\repo", "worktrees", "pr-8");
445+
const gitEntry = path.win32.join(projectRoot, ".git");
446+
const canonicalProjectRoot = path.win32.join("D:\\repo", "worktrees", "pr-8");
447+
const canonicalBackRef = path.win32.join(canonicalProjectRoot, ".git");
448+
const worktreeGitDir = path.win32.join("D:\\repo", ".git", "worktrees", "pr-8");
449+
const commondirFile = path.win32.join(worktreeGitDir, "commondir");
450+
const gitdirBackRefFile = path.win32.join(worktreeGitDir, "gitdir");
451+
const sharedRepoRoot = "D:\\repo";
452+
const sharedGitDir = path.win32.join(sharedRepoRoot, ".git");
453+
const normalize = (value: string) => path.win32.normalize(value).toLowerCase();
454+
const aliasPrefix = normalize(path.win32.join("X:\\repo"));
455+
const canonicalBackRefNormalized = normalize(canonicalBackRef);
456+
457+
mockedRealpathSyncNative.mockImplementation((value) => {
458+
const normalizedValue = normalize(String(value));
459+
if (normalizedValue === canonicalBackRefNormalized) {
460+
throw new Error("simulated native realpath failure");
461+
}
462+
if (normalizedValue.startsWith(aliasPrefix)) {
463+
const suffix = normalizedValue.slice(aliasPrefix.length);
464+
return path.win32.join("D:\\repo", suffix.replace(/^\\+/, ""));
465+
}
466+
return String(value);
467+
});
468+
mockedRealpathSync.mockImplementation((value) => String(value));
469+
470+
mockedExistsSync.mockImplementation((candidate) => {
471+
if (typeof candidate !== "string") return false;
472+
const normalizedCandidate = normalize(candidate);
473+
return (
474+
normalizedCandidate === normalize(gitEntry) ||
475+
normalizedCandidate === normalize(commondirFile) ||
476+
normalizedCandidate === normalize(gitdirBackRefFile) ||
477+
normalizedCandidate === normalize(sharedGitDir)
478+
);
479+
});
480+
mockedStatSync.mockImplementation((candidate) => {
481+
expect(normalize(String(candidate))).toBe(normalize(gitEntry));
482+
return buildMockStat({ isDirectory: false, isFile: true });
483+
});
484+
mockedReadFileSync.mockImplementation((candidate) => {
485+
if (typeof candidate !== "string") {
486+
throw new Error(`Unexpected read path: ${String(candidate)}`);
487+
}
488+
const normalizedCandidate = normalize(candidate);
489+
if (normalizedCandidate === normalize(gitEntry)) {
490+
return `gitdir: ${worktreeGitDir}\n`;
491+
}
492+
if (normalizedCandidate === normalize(commondirFile)) {
493+
return "..\\..\\\n";
494+
}
495+
if (normalizedCandidate === normalize(gitdirBackRefFile)) {
496+
return `${canonicalBackRef}\n`;
497+
}
498+
throw new Error(`Unexpected read path: ${String(candidate)}`);
499+
});
500+
501+
const resolved = resolveProjectStorageIdentityRoot(projectRoot);
502+
expect(normalize(resolved)).toBe(normalize(sharedRepoRoot));
503+
});
504+
505+
it("falls back when realpathSync.native is unavailable and realpathSync throws", () => {
506+
const projectRoot = path.win32.join("X:\\repo", "worktrees", "pr-8");
507+
const gitEntry = path.win32.join(projectRoot, ".git");
508+
const canonicalProjectRoot = path.win32.join("D:\\repo", "worktrees", "pr-8");
509+
const canonicalBackRef = path.win32.join(canonicalProjectRoot, ".git");
510+
const worktreeGitDir = path.win32.join("D:\\repo", ".git", "worktrees", "pr-8");
511+
const commondirFile = path.win32.join(worktreeGitDir, "commondir");
512+
const gitdirBackRefFile = path.win32.join(worktreeGitDir, "gitdir");
513+
const sharedRepoRoot = "D:\\repo";
514+
const sharedGitDir = path.win32.join(sharedRepoRoot, ".git");
515+
const normalize = (value: string) => path.win32.normalize(value).toLowerCase();
516+
const aliasPrefix = normalize(path.win32.join("X:\\repo"));
517+
const canonicalBackRefNormalized = normalize(canonicalBackRef);
518+
const originalNative = realpathSync.native;
519+
520+
Object.defineProperty(realpathSync, "native", {
521+
value: undefined,
522+
configurable: true,
523+
writable: true,
524+
});
525+
526+
try {
527+
mockedRealpathSync.mockImplementation((value) => {
528+
const normalizedValue = normalize(String(value));
529+
if (normalizedValue === canonicalBackRefNormalized) {
530+
throw new Error("simulated realpath fallback failure");
531+
}
532+
if (normalizedValue.startsWith(aliasPrefix)) {
533+
const suffix = normalizedValue.slice(aliasPrefix.length);
534+
return path.win32.join("D:\\repo", suffix.replace(/^\\+/, ""));
535+
}
536+
return String(value);
537+
});
538+
539+
mockedExistsSync.mockImplementation((candidate) => {
540+
if (typeof candidate !== "string") return false;
541+
const normalizedCandidate = normalize(candidate);
542+
return (
543+
normalizedCandidate === normalize(gitEntry) ||
544+
normalizedCandidate === normalize(commondirFile) ||
545+
normalizedCandidate === normalize(gitdirBackRefFile) ||
546+
normalizedCandidate === normalize(sharedGitDir)
547+
);
548+
});
549+
mockedStatSync.mockImplementation((candidate) => {
550+
expect(normalize(String(candidate))).toBe(normalize(gitEntry));
551+
return buildMockStat({ isDirectory: false, isFile: true });
552+
});
553+
mockedReadFileSync.mockImplementation((candidate) => {
554+
if (typeof candidate !== "string") {
555+
throw new Error(`Unexpected read path: ${String(candidate)}`);
556+
}
557+
const normalizedCandidate = normalize(candidate);
558+
if (normalizedCandidate === normalize(gitEntry)) {
559+
return `gitdir: ${worktreeGitDir}\n`;
560+
}
561+
if (normalizedCandidate === normalize(commondirFile)) {
562+
return "..\\..\\\n";
563+
}
564+
if (normalizedCandidate === normalize(gitdirBackRefFile)) {
565+
return `${canonicalBackRef}\n`;
566+
}
567+
throw new Error(`Unexpected read path: ${String(candidate)}`);
568+
});
569+
570+
const resolved = resolveProjectStorageIdentityRoot(projectRoot);
571+
expect(normalize(resolved)).toBe(normalize(sharedRepoRoot));
572+
} finally {
573+
Object.defineProperty(realpathSync, "native", {
574+
value: originalNative,
575+
configurable: true,
576+
writable: true,
577+
});
578+
}
579+
});
580+
443581
it("falls back to project root for forged worktree pointers", () => {
444582
const projectRoot = "/repo/attacker";
445583
const gitEntry = path.join(projectRoot, ".git");

0 commit comments

Comments
 (0)