Skip to content

Commit 6837713

Browse files
committed
whatever
1 parent e7f6995 commit 6837713

1 file changed

Lines changed: 218 additions & 0 deletions

File tree

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
import assert from 'assert';
2+
import * as sinon from 'sinon';
3+
import { LogOutputChannel } from 'vscode';
4+
import * as childProcessApis from '../../../common/childProcess.apis';
5+
import { EventNames } from '../../../common/telemetry/constants';
6+
import * as telemetrySender from '../../../common/telemetry/sender';
7+
import { isUvInstalled, resetUvInstallationCache } from '../../../managers/builtin/helpers';
8+
import { MockChildProcess } from '../../mocks/mockChildProcess';
9+
10+
suite('Helpers - isUvInstalled', () => {
11+
let mockLog: LogOutputChannel;
12+
let spawnStub: sinon.SinonStub;
13+
let sendTelemetryEventStub: sinon.SinonStub;
14+
15+
setup(() => {
16+
// Reset UV installation cache before each test to ensure clean state
17+
resetUvInstallationCache();
18+
19+
// Create a mock for LogOutputChannel
20+
mockLog = {
21+
info: sinon.stub(),
22+
error: sinon.stub(),
23+
warn: sinon.stub(),
24+
append: sinon.stub(),
25+
debug: sinon.stub(),
26+
trace: sinon.stub(),
27+
show: sinon.stub(),
28+
hide: sinon.stub(),
29+
dispose: sinon.stub(),
30+
clear: sinon.stub(),
31+
replace: sinon.stub(),
32+
appendLine: sinon.stub(),
33+
name: 'test-log',
34+
logLevel: 1,
35+
onDidChangeLogLevel: sinon.stub() as LogOutputChannel['onDidChangeLogLevel'],
36+
} as unknown as LogOutputChannel;
37+
38+
// Stub childProcess.apis spawnProcess
39+
spawnStub = sinon.stub(childProcessApis, 'spawnProcess');
40+
41+
// Stub telemetry
42+
sendTelemetryEventStub = sinon.stub(telemetrySender, 'sendTelemetryEvent');
43+
});
44+
45+
teardown(() => {
46+
sinon.restore();
47+
});
48+
49+
test('should return true when uv --version succeeds', async () => {
50+
// Arrange - Create mock process that simulates successful uv --version
51+
const mockProcess = new MockChildProcess('uv', ['--version']);
52+
spawnStub.withArgs('uv', ['--version']).returns(mockProcess);
53+
54+
// Act - Call isUvInstalled and simulate successful process
55+
const resultPromise = isUvInstalled(mockLog);
56+
57+
// Simulate successful uv --version command
58+
setTimeout(() => {
59+
mockProcess.stdout?.emit('data', 'uv 0.1.0\n');
60+
mockProcess.emit('exit', 0, null);
61+
}, 10);
62+
63+
const result = await resultPromise;
64+
65+
// Assert
66+
assert.strictEqual(result, true);
67+
assert(
68+
sendTelemetryEventStub.calledWith(EventNames.VENV_USING_UV),
69+
'Should send telemetry event when UV is available',
70+
);
71+
assert(spawnStub.calledWith('uv', ['--version']), 'Should spawn uv --version command');
72+
});
73+
74+
test('should return false when uv --version fails with non-zero exit code', async () => {
75+
// Arrange - Create mock process that simulates failed uv --version
76+
const mockProcess = new MockChildProcess('uv', ['--version']);
77+
spawnStub.withArgs('uv', ['--version']).returns(mockProcess);
78+
79+
// Act - Call isUvInstalled and simulate failed process
80+
const resultPromise = isUvInstalled(mockLog);
81+
82+
// Simulate failed uv --version command
83+
setTimeout(() => {
84+
mockProcess.emit('exit', 1, null);
85+
}, 10);
86+
87+
const result = await resultPromise;
88+
89+
// Assert
90+
assert.strictEqual(result, false);
91+
assert(sendTelemetryEventStub.notCalled, 'Should not send telemetry event when UV is not available');
92+
assert(spawnStub.calledWith('uv', ['--version']), 'Should spawn uv --version command');
93+
});
94+
95+
test('should return false when uv command is not found (error event)', async () => {
96+
// Arrange - Create mock process that simulates command not found
97+
const mockProcess = new MockChildProcess('uv', ['--version']);
98+
spawnStub.withArgs('uv', ['--version']).returns(mockProcess);
99+
100+
// Act - Call isUvInstalled and simulate error (command not found)
101+
const resultPromise = isUvInstalled(mockLog);
102+
103+
// Simulate error event (e.g., command not found)
104+
setTimeout(() => {
105+
mockProcess.emit('error', new Error('spawn uv ENOENT'));
106+
}, 10);
107+
108+
const result = await resultPromise;
109+
110+
// Assert
111+
assert.strictEqual(result, false);
112+
assert(sendTelemetryEventStub.notCalled, 'Should not send telemetry event when UV command is not found');
113+
assert(spawnStub.calledWith('uv', ['--version']), 'Should spawn uv --version command');
114+
});
115+
116+
test('should log uv --version command when logger provided', async () => {
117+
// Arrange - Create mock process
118+
const mockProcess = new MockChildProcess('uv', ['--version']);
119+
spawnStub.withArgs('uv', ['--version']).returns(mockProcess);
120+
121+
// Act - Call isUvInstalled with logger
122+
const resultPromise = isUvInstalled(mockLog);
123+
124+
// Simulate successful command with output
125+
setTimeout(() => {
126+
mockProcess.stdout?.emit('data', 'uv 0.1.0\n');
127+
mockProcess.emit('exit', 0, null);
128+
}, 10);
129+
130+
await resultPromise;
131+
132+
// Assert
133+
assert(
134+
(mockLog.info as sinon.SinonStub).calledWith('Running: uv --version'),
135+
'Should log the command being run',
136+
);
137+
assert((mockLog.info as sinon.SinonStub).calledWith('uv 0.1.0\n'), 'Should log the command output');
138+
});
139+
140+
test('should work without logger', async () => {
141+
// Arrange - Create mock process
142+
const mockProcess = new MockChildProcess('uv', ['--version']);
143+
spawnStub.withArgs('uv', ['--version']).returns(mockProcess);
144+
145+
// Act - Call isUvInstalled without logger
146+
const resultPromise = isUvInstalled();
147+
148+
// Simulate successful command
149+
setTimeout(() => {
150+
mockProcess.stdout?.emit('data', 'uv 0.1.0\n');
151+
mockProcess.emit('exit', 0, null);
152+
}, 10);
153+
154+
const result = await resultPromise;
155+
156+
// Assert
157+
assert.strictEqual(result, true);
158+
assert(spawnStub.calledWith('uv', ['--version']), 'Should spawn uv --version command even without logger');
159+
});
160+
161+
test('should return cached result on subsequent calls', async () => {
162+
// Arrange - Create mock process for first call
163+
const mockProcess = new MockChildProcess('uv', ['--version']);
164+
spawnStub.withArgs('uv', ['--version']).returns(mockProcess);
165+
166+
// Act - First call
167+
const firstCallPromise = isUvInstalled(mockLog);
168+
169+
// Simulate successful command
170+
setTimeout(() => {
171+
mockProcess.stdout?.emit('data', 'uv 0.1.0\n');
172+
mockProcess.emit('exit', 0, null);
173+
}, 10);
174+
175+
const firstResult = await firstCallPromise;
176+
177+
// Act - Second call (should use cached result)
178+
const secondResult = await isUvInstalled(mockLog);
179+
180+
// Assert
181+
assert.strictEqual(firstResult, true);
182+
assert.strictEqual(secondResult, true);
183+
assert(spawnStub.calledOnce, 'Should only spawn process once, second call should use cached result');
184+
});
185+
186+
test('should check uv installation again after cache reset', async () => {
187+
// Arrange - First call
188+
let mockProcess = new MockChildProcess('uv', ['--version']);
189+
spawnStub.withArgs('uv', ['--version']).returns(mockProcess);
190+
191+
const firstCallPromise = isUvInstalled(mockLog);
192+
setTimeout(() => {
193+
mockProcess.stdout?.emit('data', 'uv 0.1.0\n');
194+
mockProcess.emit('exit', 0, null);
195+
}, 10);
196+
197+
const firstResult = await firstCallPromise;
198+
199+
// Act - Reset cache
200+
resetUvInstallationCache();
201+
202+
// Arrange - Second call after reset
203+
mockProcess = new MockChildProcess('uv', ['--version']);
204+
spawnStub.withArgs('uv', ['--version']).returns(mockProcess);
205+
206+
const secondCallPromise = isUvInstalled(mockLog);
207+
setTimeout(() => {
208+
mockProcess.emit('exit', 1, null); // Simulate failure this time
209+
}, 10);
210+
211+
const secondResult = await secondCallPromise;
212+
213+
// Assert
214+
assert.strictEqual(firstResult, true);
215+
assert.strictEqual(secondResult, false);
216+
assert(spawnStub.calledTwice, 'Should spawn process twice after cache reset');
217+
});
218+
});

0 commit comments

Comments
 (0)