|
12 | 12 | * - pathLikeToString() converts Buffer/URL to string |
13 | 13 | * - relativeResolve() resolves relative paths |
14 | 14 | * - toUnixPath() converts Windows paths to Unix-style POSIX paths for Git Bash tools |
| 15 | + * - fromUnixPath() converts MSYS/Unix-style paths back to native Windows paths |
15 | 16 | * Used throughout Socket tools for cross-platform path handling. |
16 | 17 | */ |
17 | 18 |
|
18 | 19 | import process from 'node:process' |
19 | 20 | import { describe, expect, it } from 'vitest' |
20 | 21 | import { |
| 22 | + fromUnixPath, |
21 | 23 | isAbsolute, |
22 | 24 | isNodeModules, |
23 | 25 | isPath, |
@@ -83,6 +85,120 @@ describe('paths/normalize', () => { |
83 | 85 | }) |
84 | 86 | }) |
85 | 87 |
|
| 88 | + describe('fromUnixPath', () => { |
| 89 | + const isWindows = process.platform === 'win32' |
| 90 | + |
| 91 | + it('should convert MSYS drive letter paths to Windows format', () => { |
| 92 | + if (isWindows) { |
| 93 | + expect(fromUnixPath('/c/Users/name/file.txt')).toBe( |
| 94 | + 'C:/Users/name/file.txt', |
| 95 | + ) |
| 96 | + expect(fromUnixPath('/d/projects/foo/bar')).toBe('D:/projects/foo/bar') |
| 97 | + } |
| 98 | + }) |
| 99 | + |
| 100 | + it('should convert lowercase drive letters to uppercase', () => { |
| 101 | + if (isWindows) { |
| 102 | + expect(fromUnixPath('/c/path')).toBe('C:/path') |
| 103 | + expect(fromUnixPath('/d/path')).toBe('D:/path') |
| 104 | + expect(fromUnixPath('/z/path')).toBe('Z:/path') |
| 105 | + } |
| 106 | + }) |
| 107 | + |
| 108 | + it('should handle all drive letters a-z', () => { |
| 109 | + if (isWindows) { |
| 110 | + expect(fromUnixPath('/a/path')).toBe('A:/path') |
| 111 | + expect(fromUnixPath('/e/path')).toBe('E:/path') |
| 112 | + expect(fromUnixPath('/z/path')).toBe('Z:/path') |
| 113 | + } |
| 114 | + }) |
| 115 | + |
| 116 | + it('should handle bare drive letter path', () => { |
| 117 | + if (isWindows) { |
| 118 | + expect(fromUnixPath('/c')).toBe('C:/') |
| 119 | + } |
| 120 | + }) |
| 121 | + |
| 122 | + it('should not convert non-drive Unix paths', () => { |
| 123 | + if (isWindows) { |
| 124 | + // Paths that don't match the /x/ MSYS drive pattern |
| 125 | + expect(fromUnixPath('/home/user/file')).toBe('/home/user/file') |
| 126 | + expect(fromUnixPath('/usr/local/bin')).toBe('/usr/local/bin') |
| 127 | + } |
| 128 | + }) |
| 129 | + |
| 130 | + it('should leave Unix paths unchanged on Unix', () => { |
| 131 | + if (!isWindows) { |
| 132 | + expect(fromUnixPath('/home/user/file')).toBe('/home/user/file') |
| 133 | + expect(fromUnixPath('/usr/local/bin')).toBe('/usr/local/bin') |
| 134 | + expect(fromUnixPath('/c/Users/name')).toBe('/c/Users/name') |
| 135 | + } |
| 136 | + }) |
| 137 | + |
| 138 | + it('should normalize paths on Unix', () => { |
| 139 | + if (!isWindows) { |
| 140 | + expect(fromUnixPath('/usr/local/../bin')).toBe('/usr/bin') |
| 141 | + expect(fromUnixPath('/usr//local///bin')).toBe('/usr/local/bin') |
| 142 | + } |
| 143 | + }) |
| 144 | + |
| 145 | + it('should handle relative paths', () => { |
| 146 | + const result1 = fromUnixPath('./src/index.ts') |
| 147 | + const result2 = fromUnixPath('../lib/utils') |
| 148 | + expect(result1).toContain('src') |
| 149 | + expect(result2).toContain('lib') |
| 150 | + }) |
| 151 | + |
| 152 | + it('should handle empty string', () => { |
| 153 | + expect(fromUnixPath('')).toBe('.') |
| 154 | + }) |
| 155 | + |
| 156 | + it('should handle paths with spaces', () => { |
| 157 | + if (isWindows) { |
| 158 | + expect(fromUnixPath('/c/Program Files/App')).toBe( |
| 159 | + 'C:/Program Files/App', |
| 160 | + ) |
| 161 | + } |
| 162 | + }) |
| 163 | + |
| 164 | + it('should handle paths with special characters', () => { |
| 165 | + if (isWindows) { |
| 166 | + expect(fromUnixPath('/c/Users/name/file (1).txt')).toBe( |
| 167 | + 'C:/Users/name/file (1).txt', |
| 168 | + ) |
| 169 | + expect(fromUnixPath('/d/projects/@scope/package')).toBe( |
| 170 | + 'D:/projects/@scope/package', |
| 171 | + ) |
| 172 | + } |
| 173 | + }) |
| 174 | + |
| 175 | + it('should handle Buffer input', () => { |
| 176 | + if (isWindows) { |
| 177 | + const buffer = Buffer.from('/c/Users/name') |
| 178 | + expect(fromUnixPath(buffer)).toBe('C:/Users/name') |
| 179 | + } else { |
| 180 | + const buffer = Buffer.from('/usr/local') |
| 181 | + expect(fromUnixPath(buffer)).toBe('/usr/local') |
| 182 | + } |
| 183 | + }) |
| 184 | + |
| 185 | + it('should be the inverse of toUnixPath on Windows', () => { |
| 186 | + if (isWindows) { |
| 187 | + // Round-trip: Windows → Unix → Windows |
| 188 | + const original = 'C:/Users/name/file.txt' |
| 189 | + const unix = toUnixPath(original) |
| 190 | + const backToWindows = fromUnixPath(unix) |
| 191 | + expect(backToWindows).toBe(original) |
| 192 | + } |
| 193 | + }) |
| 194 | + |
| 195 | + it('should handle root path', () => { |
| 196 | + if (!isWindows) { |
| 197 | + expect(fromUnixPath('/')).toBe('/') |
| 198 | + } |
| 199 | + }) |
| 200 | + }) |
| 201 | + |
86 | 202 | describe('isAbsolute', () => { |
87 | 203 | it('should detect Unix absolute paths', () => { |
88 | 204 | expect(isAbsolute('/usr/local')).toBe(true) |
|
0 commit comments