|
| 1 | +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" |
1 | 2 | import * as vscode from "vscode" |
2 | 3 | import { userInfo } from "os" |
3 | 4 | import { getShell } from "../shell" |
4 | 5 |
|
| 6 | +// Mock vscode module |
| 7 | +vi.mock("vscode", () => ({ |
| 8 | + workspace: { |
| 9 | + getConfiguration: vi.fn(), |
| 10 | + }, |
| 11 | +})) |
| 12 | + |
5 | 13 | // Mock the os module |
6 | 14 | vi.mock("os", () => ({ |
7 | 15 | userInfo: vi.fn(() => ({ shell: null })), |
@@ -74,6 +82,56 @@ describe("Shell Detection Tests", () => { |
74 | 82 | expect(getShell()).toBe("C:\\Program Files\\PowerShell\\7\\pwsh.exe") |
75 | 83 | }) |
76 | 84 |
|
| 85 | + it("should handle array path from VSCode terminal profile", () => { |
| 86 | + // Mock VSCode configuration with array path |
| 87 | + const mockConfig = { |
| 88 | + get: vi.fn((key: string) => { |
| 89 | + if (key === "defaultProfile.windows") return "PowerShell" |
| 90 | + if (key === "profiles.windows") { |
| 91 | + return { |
| 92 | + PowerShell: { |
| 93 | + // VSCode API may return path as an array |
| 94 | + path: ["C:\\Program Files\\PowerShell\\7\\pwsh.exe", "pwsh.exe"], |
| 95 | + }, |
| 96 | + } |
| 97 | + } |
| 98 | + return undefined |
| 99 | + }), |
| 100 | + } |
| 101 | + |
| 102 | + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue(mockConfig as any) |
| 103 | + |
| 104 | + const result = getShell() |
| 105 | + // Should use the first element of the array |
| 106 | + expect(result).toBe("C:\\Program Files\\PowerShell\\7\\pwsh.exe") |
| 107 | + }) |
| 108 | + |
| 109 | + it("should handle empty array path and fall back to defaults", () => { |
| 110 | + // Mock VSCode configuration with empty array path |
| 111 | + const mockConfig = { |
| 112 | + get: vi.fn((key: string) => { |
| 113 | + if (key === "defaultProfile.windows") return "Custom" |
| 114 | + if (key === "profiles.windows") { |
| 115 | + return { |
| 116 | + Custom: { |
| 117 | + path: [], // Empty array |
| 118 | + }, |
| 119 | + } |
| 120 | + } |
| 121 | + return undefined |
| 122 | + }), |
| 123 | + } |
| 124 | + |
| 125 | + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue(mockConfig as any) |
| 126 | + |
| 127 | + // Mock environment variable |
| 128 | + process.env.COMSPEC = "C:\\Windows\\System32\\cmd.exe" |
| 129 | + |
| 130 | + const result = getShell() |
| 131 | + // Should fall back to cmd.exe |
| 132 | + expect(result).toBe("C:\\Windows\\System32\\cmd.exe") |
| 133 | + }) |
| 134 | + |
77 | 135 | it("uses PowerShell 7 path if source is 'PowerShell' but no explicit path", () => { |
78 | 136 | mockVsCodeConfig("windows", "PowerShell", { |
79 | 137 | PowerShell: { source: "PowerShell" }, |
@@ -152,6 +210,29 @@ describe("Shell Detection Tests", () => { |
152 | 210 | expect(getShell()).toBe("/usr/local/bin/fish") |
153 | 211 | }) |
154 | 212 |
|
| 213 | + it("should handle array path from VSCode terminal profile", () => { |
| 214 | + // Mock VSCode configuration with array path |
| 215 | + const mockConfig = { |
| 216 | + get: vi.fn((key: string) => { |
| 217 | + if (key === "defaultProfile.osx") return "zsh" |
| 218 | + if (key === "profiles.osx") { |
| 219 | + return { |
| 220 | + zsh: { |
| 221 | + path: ["/opt/homebrew/bin/zsh", "/bin/zsh"], |
| 222 | + }, |
| 223 | + } |
| 224 | + } |
| 225 | + return undefined |
| 226 | + }), |
| 227 | + } |
| 228 | + |
| 229 | + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue(mockConfig as any) |
| 230 | + |
| 231 | + const result = getShell() |
| 232 | + // Should use the first element of the array |
| 233 | + expect(result).toBe("/opt/homebrew/bin/zsh") |
| 234 | + }) |
| 235 | + |
155 | 236 | it("falls back to userInfo().shell if no VS Code config is available", () => { |
156 | 237 | vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any |
157 | 238 | vi.mocked(userInfo).mockReturnValue({ shell: "/opt/homebrew/bin/zsh" } as any) |
@@ -185,6 +266,29 @@ describe("Shell Detection Tests", () => { |
185 | 266 | expect(getShell()).toBe("/usr/bin/fish") |
186 | 267 | }) |
187 | 268 |
|
| 269 | + it("should handle array path from VSCode terminal profile", () => { |
| 270 | + // Mock VSCode configuration with array path |
| 271 | + const mockConfig = { |
| 272 | + get: vi.fn((key: string) => { |
| 273 | + if (key === "defaultProfile.linux") return "bash" |
| 274 | + if (key === "profiles.linux") { |
| 275 | + return { |
| 276 | + bash: { |
| 277 | + path: ["/usr/local/bin/bash", "/bin/bash"], |
| 278 | + }, |
| 279 | + } |
| 280 | + } |
| 281 | + return undefined |
| 282 | + }), |
| 283 | + } |
| 284 | + |
| 285 | + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue(mockConfig as any) |
| 286 | + |
| 287 | + const result = getShell() |
| 288 | + // Should use the first element of the array |
| 289 | + expect(result).toBe("/usr/local/bin/bash") |
| 290 | + }) |
| 291 | + |
188 | 292 | it("falls back to userInfo().shell if no VS Code config is available", () => { |
189 | 293 | vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any |
190 | 294 | vi.mocked(userInfo).mockReturnValue({ shell: "/usr/bin/zsh" } as any) |
@@ -281,6 +385,57 @@ describe("Shell Detection Tests", () => { |
281 | 385 | expect(getShell()).toBe("/bin/bash") |
282 | 386 | }) |
283 | 387 |
|
| 388 | + it("should validate array shell paths and use first allowed", () => { |
| 389 | + Object.defineProperty(process, "platform", { value: "win32" }) |
| 390 | + |
| 391 | + const mockConfig = { |
| 392 | + get: vi.fn((key: string) => { |
| 393 | + if (key === "defaultProfile.windows") return "PowerShell" |
| 394 | + if (key === "profiles.windows") { |
| 395 | + return { |
| 396 | + PowerShell: { |
| 397 | + path: ["C:\\Program Files\\PowerShell\\7\\pwsh.exe", "pwsh"], |
| 398 | + }, |
| 399 | + } |
| 400 | + } |
| 401 | + return undefined |
| 402 | + }), |
| 403 | + } |
| 404 | + |
| 405 | + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue(mockConfig as any) |
| 406 | + |
| 407 | + const result = getShell() |
| 408 | + // Should return the first allowed shell from the array |
| 409 | + expect(result).toBe("C:\\Program Files\\PowerShell\\7\\pwsh.exe") |
| 410 | + }) |
| 411 | + |
| 412 | + it("should reject non-allowed shell paths and fall back to safe defaults", () => { |
| 413 | + Object.defineProperty(process, "platform", { value: "win32" }) |
| 414 | + |
| 415 | + const mockConfig = { |
| 416 | + get: vi.fn((key: string) => { |
| 417 | + if (key === "defaultProfile.windows") return "Malicious" |
| 418 | + if (key === "profiles.windows") { |
| 419 | + return { |
| 420 | + Malicious: { |
| 421 | + path: "C:\\malicious\\shell.exe", |
| 422 | + }, |
| 423 | + } |
| 424 | + } |
| 425 | + return undefined |
| 426 | + }), |
| 427 | + } |
| 428 | + |
| 429 | + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue(mockConfig as any) |
| 430 | + |
| 431 | + // Mock environment to provide a fallback |
| 432 | + process.env.COMSPEC = "C:\\Windows\\System32\\cmd.exe" |
| 433 | + |
| 434 | + const result = getShell() |
| 435 | + // Should fall back to safe default (cmd.exe) |
| 436 | + expect(result).toBe("C:\\Windows\\System32\\cmd.exe") |
| 437 | + }) |
| 438 | + |
284 | 439 | it("should validate shells from VS Code config", () => { |
285 | 440 | Object.defineProperty(process, "platform", { value: "darwin" }) |
286 | 441 | mockVsCodeConfig("osx", "MyCustomShell", { |
|
0 commit comments