|
1 | 1 | import { afterEach, beforeEach, describe, expect, test } from "bun:test"; |
2 | 2 | import { mkdirSync, rmSync, writeFileSync } from "node:fs"; |
3 | 3 | import { tmpdir } from "node:os"; |
4 | | -import { join } from "node:path"; |
| 4 | +import { join, posix, win32 } from "node:path"; |
5 | 5 | import { |
6 | 6 | analyzeProjectCodexConfig, |
7 | 7 | collectProjectCodexConfigWarnings, |
8 | 8 | getCachedProjectConfigDiagnostics, |
9 | 9 | isGlobalOpencodexRoutingActive, |
10 | 10 | invalidateProjectConfigDiagnosticsCache, |
11 | 11 | parseTrustedProjectPathsFromCodexConfig, |
| 12 | + relPath, |
12 | 13 | resolveEffectiveProjectModelProvider, |
13 | 14 | } from "../src/codex/project-config-warnings"; |
14 | 15 |
|
| 16 | +describe("relPath home containment (devlog 260715_cross_platform_audit/030)", () => { |
| 17 | + let savedUserProfile: string | undefined; |
| 18 | + let savedHome: string | undefined; |
| 19 | + |
| 20 | + beforeEach(() => { |
| 21 | + savedUserProfile = process.env.USERPROFILE; |
| 22 | + savedHome = process.env.HOME; |
| 23 | + }); |
| 24 | + |
| 25 | + afterEach(() => { |
| 26 | + if (savedUserProfile === undefined) delete process.env.USERPROFILE; else process.env.USERPROFILE = savedUserProfile; |
| 27 | + if (savedHome === undefined) delete process.env.HOME; else process.env.HOME = savedHome; |
| 28 | + }); |
| 29 | + |
| 30 | + function setHome(value: string) { |
| 31 | + process.env.USERPROFILE = value; |
| 32 | + delete process.env.HOME; |
| 33 | + } |
| 34 | + |
| 35 | + test("win32: contained descendants render as ~/, exact home as ~", () => { |
| 36 | + setHome("C:\\Users\\bob"); |
| 37 | + expect(relPath("C:\\Users\\bob\\proj\\.codex\\config.toml", win32)).toBe("~/proj/.codex/config.toml"); |
| 38 | + expect(relPath("C:\\Users\\bob", win32)).toBe("~"); |
| 39 | + // relative() case-folds on win32 (drive letters and components). |
| 40 | + expect(relPath("c:\\users\\bob\\x", win32)).toBe("~/x"); |
| 41 | + }); |
| 42 | + |
| 43 | + test("win32: sibling prefix (bob vs bob2) is NOT rendered as home", () => { |
| 44 | + setHome("C:\\Users\\bob"); |
| 45 | + expect(relPath("C:\\Users\\bob2\\proj\\config.toml", win32)).toBe("C:\\Users\\bob2\\proj\\config.toml"); |
| 46 | + }); |
| 47 | + |
| 48 | + test("win32: parent and cross-drive paths stay absolute", () => { |
| 49 | + setHome("C:\\Users\\bob"); |
| 50 | + expect(relPath("C:\\Users", win32)).toBe("C:\\Users"); |
| 51 | + expect(relPath("D:\\work\\config.toml", win32)).toBe("D:\\work\\config.toml"); |
| 52 | + }); |
| 53 | + |
| 54 | + test("posix: comparison is case-sensitive (no false ~ for different-case home)", () => { |
| 55 | + setHome("/home/Bob"); |
| 56 | + expect(relPath("/home/bob/x", posix)).toBe("/home/bob/x"); |
| 57 | + expect(relPath("/home/Bob/x", posix)).toBe("~/x"); |
| 58 | + }); |
| 59 | + |
| 60 | + test("no home env leaves paths untouched", () => { |
| 61 | + delete process.env.USERPROFILE; |
| 62 | + delete process.env.HOME; |
| 63 | + expect(relPath("/anywhere/x", posix)).toBe("/anywhere/x"); |
| 64 | + }); |
| 65 | +}); |
| 66 | + |
15 | 67 | let testDir = ""; |
16 | 68 | let previousHome: string | undefined; |
17 | 69 | let previousCodexHome: string | undefined; |
|
0 commit comments