Skip to content

Commit 21ad9eb

Browse files
committed
test(coverage): windows-shims.mts to 94.74% (was 57.89%)
Adds 14 tests covering both helpers across POSIX + Windows modes: - resolveBinPathSync: missing file, no-shim file, npm/pnpm/yarn shim extraction (absolute + relative), readFileSync throw fallback - preferWindowsCmdShim: WIN32-false POSIX bail, non-absolute path bail (line 68-69), pre-existing extension bail (line 73-74), basename mismatch bail (line 79-80), .cmd shim found (line 83-84), .cmd shim missing fallback, case-insensitive basename comparison WIN32 toggling done via vi.mock + a hoisted holder so each test can flip the platform without re-importing the SUT.
1 parent cf26819 commit 21ad9eb

1 file changed

Lines changed: 180 additions & 0 deletions

File tree

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/**
2+
* Unit tests for the Windows-shim resolution helpers.
3+
*
4+
* The helpers behave as no-ops on POSIX, so most assertions pivot on
5+
* stubbing the WIN32 constant from @socketsecurity/lib via vi.mock().
6+
*/
7+
8+
import { describe, expect, it, vi } from 'vitest'
9+
10+
const mockExistsSync = vi.hoisted(() => vi.fn())
11+
const mockReadFileSync = vi.hoisted(() => vi.fn())
12+
13+
// Mock fs so each test can dictate file existence and shim contents.
14+
vi.mock('node:fs', async importOriginal => {
15+
const actual: any = await importOriginal()
16+
return {
17+
...actual,
18+
default: {
19+
...actual.default,
20+
existsSync: mockExistsSync,
21+
readFileSync: mockReadFileSync,
22+
},
23+
existsSync: mockExistsSync,
24+
readFileSync: mockReadFileSync,
25+
}
26+
})
27+
28+
// Toggle the WIN32 export per test. Ships at module load, so we re-import
29+
// the SUT inside each branch that needs a different platform.
30+
const mockWin32 = vi.hoisted(() => ({ WIN32: false }))
31+
vi.mock('@socketsecurity/lib/constants/platform', () => mockWin32)
32+
33+
import {
34+
preferWindowsCmdShim,
35+
resolveBinPathSync,
36+
} from '../../../../src/utils/ecosystem/windows-shims.mts'
37+
38+
describe('windows-shims', () => {
39+
describe('resolveBinPathSync', () => {
40+
it('returns the input path verbatim when the file does not exist', () => {
41+
mockExistsSync.mockReturnValue(false)
42+
expect(resolveBinPathSync('/nonexistent/npm')).toBe('/nonexistent/npm')
43+
})
44+
45+
it('returns the input path when the file content has no shim pattern', () => {
46+
mockExistsSync.mockReturnValue(true)
47+
mockReadFileSync.mockReturnValue('echo "not a shim"\n')
48+
expect(resolveBinPathSync('/usr/bin/some-tool')).toBe(
49+
'/usr/bin/some-tool',
50+
)
51+
})
52+
53+
it('extracts the absolute npm-cli.js path from a node-style shim', () => {
54+
mockExistsSync.mockReturnValue(true)
55+
mockReadFileSync.mockReturnValue(
56+
'node "/usr/lib/node_modules/npm/bin/npm-cli.js" "$@"\n',
57+
)
58+
expect(resolveBinPathSync('/usr/local/bin/npm')).toBe(
59+
'/usr/lib/node_modules/npm/bin/npm-cli.js',
60+
)
61+
})
62+
63+
it('extracts the pnpm shim path', () => {
64+
mockExistsSync.mockReturnValue(true)
65+
mockReadFileSync.mockReturnValue(
66+
'node "/opt/pnpm/dist/pnpm.cjs" "$@"\n',
67+
)
68+
expect(resolveBinPathSync('/usr/local/bin/pnpm')).toBe(
69+
'/opt/pnpm/dist/pnpm.cjs',
70+
)
71+
})
72+
73+
it('extracts the yarn shim path (.mjs extension)', () => {
74+
mockExistsSync.mockReturnValue(true)
75+
mockReadFileSync.mockReturnValue(
76+
'node "/opt/yarn/lib/yarn.mjs" "$@"\n',
77+
)
78+
expect(resolveBinPathSync('/usr/local/bin/yarn')).toBe(
79+
'/opt/yarn/lib/yarn.mjs',
80+
)
81+
})
82+
83+
it('resolves a relative shim path against the bin dir', () => {
84+
mockExistsSync.mockReturnValue(true)
85+
mockReadFileSync.mockReturnValue('node "../lib/npm-cli.js" "$@"\n')
86+
const result = resolveBinPathSync('/usr/local/bin/npm')
87+
// path.resolve('/usr/local/bin', '../lib/npm-cli.js')
88+
expect(result).toContain('npm-cli.js')
89+
expect(result.startsWith('/')).toBe(true)
90+
})
91+
92+
it('returns the input path when readFileSync throws', () => {
93+
mockExistsSync.mockReturnValue(true)
94+
mockReadFileSync.mockImplementation(() => {
95+
throw new Error('EACCES')
96+
})
97+
expect(resolveBinPathSync('/usr/local/bin/npm')).toBe(
98+
'/usr/local/bin/npm',
99+
)
100+
})
101+
})
102+
103+
describe('preferWindowsCmdShim (POSIX)', () => {
104+
it('returns the input path verbatim on POSIX (WIN32 = false)', () => {
105+
mockWin32.WIN32 = false
106+
expect(preferWindowsCmdShim('/usr/local/bin/npm', 'npm')).toBe(
107+
'/usr/local/bin/npm',
108+
)
109+
})
110+
})
111+
112+
describe('preferWindowsCmdShim (Windows)', () => {
113+
it('returns the input for non-absolute paths (line 68-69)', () => {
114+
mockWin32.WIN32 = true
115+
try {
116+
expect(preferWindowsCmdShim('npm', 'npm')).toBe('npm')
117+
} finally {
118+
mockWin32.WIN32 = false
119+
}
120+
})
121+
122+
it('returns the input when path already has an extension (line 73-74)', () => {
123+
mockWin32.WIN32 = true
124+
try {
125+
expect(
126+
preferWindowsCmdShim('C:\\nodejs\\npm.exe', 'npm'),
127+
).toBe('C:\\nodejs\\npm.exe')
128+
} finally {
129+
mockWin32.WIN32 = false
130+
}
131+
})
132+
133+
it('returns the input when basename does not match binName (line 79-80)', () => {
134+
mockWin32.WIN32 = true
135+
try {
136+
expect(
137+
preferWindowsCmdShim('/usr/local/bin/wrong', 'npm'),
138+
).toBe('/usr/local/bin/wrong')
139+
} finally {
140+
mockWin32.WIN32 = false
141+
}
142+
})
143+
144+
it('returns the .cmd shim when one exists in the same dir (line 83-84)', () => {
145+
mockWin32.WIN32 = true
146+
mockExistsSync.mockReturnValue(true)
147+
try {
148+
const result = preferWindowsCmdShim('/usr/local/bin/npm', 'npm')
149+
// path.join → /usr/local/bin/npm.cmd
150+
expect(result).toContain('npm.cmd')
151+
} finally {
152+
mockWin32.WIN32 = false
153+
}
154+
})
155+
156+
it('falls back to input when .cmd shim does not exist (line 84)', () => {
157+
mockWin32.WIN32 = true
158+
mockExistsSync.mockReturnValue(false)
159+
try {
160+
expect(preferWindowsCmdShim('/usr/local/bin/npm', 'npm')).toBe(
161+
'/usr/local/bin/npm',
162+
)
163+
} finally {
164+
mockWin32.WIN32 = false
165+
}
166+
})
167+
168+
it('basename comparison is case-insensitive', () => {
169+
mockWin32.WIN32 = true
170+
mockExistsSync.mockReturnValue(true)
171+
try {
172+
const result = preferWindowsCmdShim('/usr/local/bin/NPM', 'npm')
173+
// Match succeeds because lowercased equality holds.
174+
expect(result).toContain('.cmd')
175+
} finally {
176+
mockWin32.WIN32 = false
177+
}
178+
})
179+
})
180+
})

0 commit comments

Comments
 (0)