Skip to content

Commit 2e8e6c3

Browse files
committed
lean windows
1 parent bb692f3 commit 2e8e6c3

File tree

1 file changed

+175
-16
lines changed

1 file changed

+175
-16
lines changed

src/test/managers/common/nativePythonFinder.getAllExtraSearchPaths.unit.test.ts

Lines changed: 175 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
3131
mockGetWorkspaceFolders = sinon.stub(workspaceApis, 'getWorkspaceFolders');
3232
mockUntildify = sinon.stub(pathUtils, 'untildify');
3333
// Also stub the namespace import version that might be used by untildifyArray
34+
// Handle both Unix (~/) and Windows-style paths
3435
sinon
3536
.stub(pathUtils, 'untildifyArray')
3637
.callsFake((paths: string[]) =>
@@ -103,8 +104,8 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
103104
assert.deepStrictEqual(result, []);
104105
});
105106

106-
test('Legacy and global paths are consolidated', async () => {
107-
// Mock → Legacy paths and globalSearchPaths both exist
107+
test('Legacy and global paths are consolidated (Unix)', async () => {
108+
// Mock → Legacy paths and globalSearchPaths both exist (Unix-style)
108109
pythonConfig.get.withArgs('venvPath').returns('/home/user/.virtualenvs');
109110
pythonConfig.get.withArgs('venvFolders').returns(['/home/user/venvs']);
110111
envConfig.inspect.withArgs('globalSearchPaths').returns({
@@ -122,8 +123,27 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
122123
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
123124
});
124125

125-
test('Legacy paths included alongside new settings', async () => {
126-
// Mock → Legacy paths exist, no globalSearchPaths
126+
test('Legacy and global paths are consolidated (Windows)', async () => {
127+
// Mock → Legacy paths and globalSearchPaths both exist (Windows-style)
128+
pythonConfig.get.withArgs('venvPath').returns('C:\\Users\\dev\\.virtualenvs');
129+
pythonConfig.get.withArgs('venvFolders').returns(['D:\\shared\\venvs']);
130+
envConfig.inspect.withArgs('globalSearchPaths').returns({
131+
globalValue: ['C:\\Users\\dev\\.virtualenvs', 'D:\\shared\\venvs', 'E:\\additional\\path'],
132+
});
133+
envConfig.inspect.withArgs('workspaceSearchPaths').returns({});
134+
135+
// Run
136+
const result = await getAllExtraSearchPaths();
137+
138+
// Assert - Should consolidate all paths (duplicates removed), normalized to forward slashes
139+
const expected = new Set(['C:/Users/dev/.virtualenvs', 'D:/shared/venvs', 'E:/additional/path']);
140+
const actual = new Set(result);
141+
assert.strictEqual(actual.size, expected.size, 'Should have correct number of unique paths');
142+
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
143+
});
144+
145+
test('Legacy paths included alongside new settings (Unix)', async () => {
146+
// Mock → Legacy paths exist, no globalSearchPaths (Unix-style)
127147
pythonConfig.get.withArgs('venvPath').returns('/home/user/.virtualenvs');
128148
pythonConfig.get.withArgs('venvFolders').returns(['/home/user/venvs', '/home/user/conda']);
129149
envConfig.inspect.withArgs('globalSearchPaths').returns({ globalValue: [] });
@@ -139,6 +159,23 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
139159
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
140160
});
141161

162+
test('Legacy paths included alongside new settings (Windows)', async () => {
163+
// Mock → Legacy paths exist, no globalSearchPaths (Windows-style)
164+
pythonConfig.get.withArgs('venvPath').returns('C:\\Users\\dev\\.virtualenvs');
165+
pythonConfig.get.withArgs('venvFolders').returns(['C:\\Users\\dev\\venvs', 'D:\\conda\\envs']);
166+
envConfig.inspect.withArgs('globalSearchPaths').returns({ globalValue: [] });
167+
envConfig.inspect.withArgs('workspaceSearchPaths').returns({});
168+
169+
// Run
170+
const result = await getAllExtraSearchPaths();
171+
172+
// Assert - Should include all legacy paths, normalized to forward slashes
173+
const expected = new Set(['C:/Users/dev/.virtualenvs', 'C:/Users/dev/venvs', 'D:/conda/envs']);
174+
const actual = new Set(result);
175+
assert.strictEqual(actual.size, expected.size, 'Should have correct number of unique paths');
176+
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
177+
});
178+
142179
test('Legacy and global paths combined with deduplication', async () => {
143180
// Mock → Some overlap between legacy and global paths
144181
pythonConfig.get.withArgs('venvPath').returns('/home/user/.virtualenvs');
@@ -184,8 +221,8 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
184221
});
185222

186223
suite('Configuration Source Tests', () => {
187-
test('Global search paths with tilde expansion', async () => {
188-
// Mock → No legacy, global paths with tildes
224+
test('Global search paths with tilde expansion (Unix)', async () => {
225+
// Mock → No legacy, global paths with tildes (Unix ~ expansion)
189226
pythonConfig.get.withArgs('venvPath').returns(undefined);
190227
pythonConfig.get.withArgs('venvFolders').returns(undefined);
191228
envConfig.inspect.withArgs('globalSearchPaths').returns({
@@ -206,8 +243,27 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
206243
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
207244
});
208245

209-
test('Workspace folder setting preferred over workspace setting', async () => {
210-
// Mock → Workspace settings at different levels
246+
test('Global search paths with absolute paths (Windows)', async () => {
247+
// Mock → No legacy, global paths with Windows absolute paths
248+
pythonConfig.get.withArgs('venvPath').returns(undefined);
249+
pythonConfig.get.withArgs('venvFolders').returns(undefined);
250+
envConfig.inspect.withArgs('globalSearchPaths').returns({
251+
globalValue: ['C:\\Users\\dev\\virtualenvs', 'D:\\conda\\envs'],
252+
});
253+
envConfig.inspect.withArgs('workspaceSearchPaths').returns({});
254+
255+
// Run
256+
const result = await getAllExtraSearchPaths();
257+
258+
// Assert - Paths normalized to forward slashes
259+
const expected = new Set(['C:/Users/dev/virtualenvs', 'D:/conda/envs']);
260+
const actual = new Set(result);
261+
assert.strictEqual(actual.size, expected.size, 'Should have correct number of unique paths');
262+
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
263+
});
264+
265+
test('Workspace folder setting preferred over workspace setting (Unix)', async () => {
266+
// Mock → Workspace settings at different levels (Unix-style)
211267
pythonConfig.get.withArgs('venvPath').returns(undefined);
212268
pythonConfig.get.withArgs('venvFolders').returns(undefined);
213269
envConfig.inspect.withArgs('globalSearchPaths').returns({ globalValue: [] });
@@ -230,6 +286,30 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
230286
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
231287
});
232288

289+
test('Workspace folder setting preferred over workspace setting (Windows)', async () => {
290+
// Mock → Workspace settings at different levels (Windows-style)
291+
pythonConfig.get.withArgs('venvPath').returns(undefined);
292+
pythonConfig.get.withArgs('venvFolders').returns(undefined);
293+
envConfig.inspect.withArgs('globalSearchPaths').returns({ globalValue: [] });
294+
envConfig.inspect.withArgs('workspaceSearchPaths').returns({
295+
workspaceValue: ['D:\\workspace-level'],
296+
workspaceFolderValue: ['C:\\folder-level\\path'],
297+
});
298+
299+
const workspace1 = Uri.file('C:\\Projects\\project1');
300+
const workspace2 = Uri.file('C:\\Projects\\project2');
301+
mockGetWorkspaceFolders.returns([{ uri: workspace1 }, { uri: workspace2 }]);
302+
303+
// Run
304+
const result = await getAllExtraSearchPaths();
305+
306+
// Assert - workspaceFolderValue takes priority, normalized to forward slashes
307+
const expected = new Set(['C:/folder-level/path']);
308+
const actual = new Set(result);
309+
assert.strictEqual(actual.size, expected.size, 'Should have correct number of unique paths');
310+
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
311+
});
312+
233313
test('Global workspace setting logs error and is ignored', async () => {
234314
// Mock → Workspace setting incorrectly set at global level
235315
pythonConfig.get.withArgs('venvPath').returns(undefined);
@@ -276,8 +356,8 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
276356
});
277357

278358
suite('Path Resolution Tests', () => {
279-
test('Absolute paths used as-is', async () => {
280-
// Mock → Mix of absolute paths
359+
test('Absolute paths used as-is (Unix)', async () => {
360+
// Mock → Mix of absolute paths (Unix-style)
281361
pythonConfig.get.withArgs('venvPath').returns(undefined);
282362
pythonConfig.get.withArgs('venvFolders').returns(undefined);
283363
envConfig.inspect.withArgs('globalSearchPaths').returns({
@@ -293,13 +373,37 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
293373
// Run
294374
const result = await getAllExtraSearchPaths();
295375

296-
// Assert - For absolute paths, they should remain unchanged regardless of platform
376+
// Assert - For absolute paths, they should remain unchanged
297377
const expected = new Set(['/absolute/path1', '/absolute/path2', '/absolute/workspace/path']);
298378
const actual = new Set(result);
299379
assert.strictEqual(actual.size, expected.size, 'Should have correct number of unique paths');
300380
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
301381
});
302382

383+
test('Absolute paths used as-is (Windows)', async () => {
384+
// Mock → Mix of absolute paths (Windows-style)
385+
pythonConfig.get.withArgs('venvPath').returns(undefined);
386+
pythonConfig.get.withArgs('venvFolders').returns(undefined);
387+
envConfig.inspect.withArgs('globalSearchPaths').returns({
388+
globalValue: ['C:\\absolute\\path1', 'D:\\absolute\\path2'],
389+
});
390+
envConfig.inspect.withArgs('workspaceSearchPaths').returns({
391+
workspaceFolderValue: ['E:\\workspace\\envs'],
392+
});
393+
394+
const workspace = Uri.file('C:\\workspace');
395+
mockGetWorkspaceFolders.returns([{ uri: workspace }]);
396+
397+
// Run
398+
const result = await getAllExtraSearchPaths();
399+
400+
// Assert - Windows paths normalized to forward slashes
401+
const expected = new Set(['C:/absolute/path1', 'D:/absolute/path2', 'E:/workspace/envs']);
402+
const actual = new Set(result);
403+
assert.strictEqual(actual.size, expected.size, 'Should have correct number of unique paths');
404+
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
405+
});
406+
303407
test('Relative paths are resolved against workspace folders', async () => {
304408
// Mock → Relative workspace paths with multiple workspace folders
305409
pythonConfig.get.withArgs('venvPath').returns(undefined);
@@ -384,8 +488,8 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
384488
assert.deepStrictEqual(result, []);
385489
});
386490

387-
test('Power user - complex mix of all source types', async () => {
388-
// Mock → Complex real-world scenario
491+
test('Power user - complex mix of all source types (Unix)', async () => {
492+
// Mock → Complex real-world scenario (Unix-style)
389493
pythonConfig.get.withArgs('venvPath').returns('/legacy/venv/path');
390494
pythonConfig.get.withArgs('venvFolders').returns(['/legacy/venvs']);
391495
envConfig.inspect.withArgs('globalSearchPaths').returns({
@@ -405,7 +509,6 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
405509
const result = await getAllExtraSearchPaths();
406510

407511
// Assert - Relative paths are resolved against workspace folders, absolutes kept as-is
408-
// Expected: 4 from legacy/global + 1 absolute workspace path + 2 resolved .venv paths
409512
assert.ok(result.includes('/legacy/venv/path'));
410513
assert.ok(result.includes('/legacy/venvs'));
411514
assert.ok(result.includes('/global/conda'));
@@ -416,8 +519,40 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
416519
assert.ok(result.some((p) => p.includes('project2') && p.endsWith('.venv')));
417520
});
418521

419-
test('Overlapping paths are deduplicated', async () => {
420-
// Mock → Duplicate paths from different sources (using absolute paths to test dedup)
522+
test('Power user - complex mix of all source types (Windows)', async () => {
523+
// Mock → Complex real-world scenario (Windows-style)
524+
pythonConfig.get.withArgs('venvPath').returns('C:\\legacy\\venv\\path');
525+
pythonConfig.get.withArgs('venvFolders').returns(['D:\\legacy\\venvs']);
526+
envConfig.inspect.withArgs('globalSearchPaths').returns({
527+
globalValue: ['C:\\legacy\\venv\\path', 'D:\\legacy\\venvs', 'E:\\global\\conda'],
528+
});
529+
envConfig.inspect.withArgs('workspaceSearchPaths').returns({
530+
workspaceFolderValue: ['.venv', 'F:\\shared\\team\\envs'],
531+
});
532+
533+
const workspace1 = Uri.file('C:\\workspace\\project1');
534+
const workspace2 = Uri.file('C:\\workspace\\project2');
535+
mockGetWorkspaceFolders.returns([{ uri: workspace1 }, { uri: workspace2 }]);
536+
537+
// Run
538+
const result = await getAllExtraSearchPaths();
539+
540+
// Assert - All paths normalized to forward slashes
541+
assert.ok(result.includes('C:/legacy/venv/path'));
542+
assert.ok(result.includes('D:/legacy/venvs'));
543+
assert.ok(result.includes('E:/global/conda'));
544+
assert.ok(result.includes('F:/shared/team/envs'));
545+
// .venv resolved against both workspace folders
546+
assert.ok(result.some((p) => p.includes('project1') && p.endsWith('.venv')));
547+
assert.ok(result.some((p) => p.includes('project2') && p.endsWith('.venv')));
548+
// Verify no backslashes remain
549+
for (const p of result) {
550+
assert.ok(!p.includes('\\'), `Path should not contain backslashes: ${p}`);
551+
}
552+
});
553+
554+
test('Overlapping paths are deduplicated (Unix)', async () => {
555+
// Mock → Duplicate paths from different sources (Unix-style)
421556
pythonConfig.get.withArgs('venvPath').returns(undefined);
422557
pythonConfig.get.withArgs('venvFolders').returns(undefined);
423558
envConfig.inspect.withArgs('globalSearchPaths').returns({
@@ -440,6 +575,30 @@ suite('getAllExtraSearchPaths Integration Tests', () => {
440575
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
441576
});
442577

578+
test('Overlapping paths are deduplicated (Windows)', async () => {
579+
// Mock → Duplicate paths from different sources (Windows-style)
580+
pythonConfig.get.withArgs('venvPath').returns(undefined);
581+
pythonConfig.get.withArgs('venvFolders').returns(undefined);
582+
envConfig.inspect.withArgs('globalSearchPaths').returns({
583+
globalValue: ['C:\\shared\\path', 'D:\\global\\unique'],
584+
});
585+
envConfig.inspect.withArgs('workspaceSearchPaths').returns({
586+
workspaceFolderValue: ['C:\\shared\\path', 'E:\\workspace\\unique'],
587+
});
588+
589+
const workspace = Uri.file('C:\\workspace');
590+
mockGetWorkspaceFolders.returns([{ uri: workspace }]);
591+
592+
// Run
593+
const result = await getAllExtraSearchPaths();
594+
595+
// Assert - Duplicates should be removed, normalized to forward slashes
596+
const expected = new Set(['C:/shared/path', 'D:/global/unique', 'E:/workspace/unique']);
597+
const actual = new Set(result);
598+
assert.strictEqual(actual.size, expected.size, 'Should have correct number of unique paths');
599+
assert.deepStrictEqual(actual, expected, 'Should contain exactly the expected paths');
600+
});
601+
443602
test('All path types consolidated together', async () => {
444603
// Mock → Multiple path types from different sources
445604
pythonConfig.get.withArgs('venvPath').returns('/legacy/path');

0 commit comments

Comments
 (0)