|
| 1 | +// Copyright (c) Microsoft Corporation. All rights reserved. |
| 2 | +// Licensed under the MIT License. |
| 3 | + |
| 4 | +import assert from 'assert'; |
| 5 | +import * as sinon from 'sinon'; |
| 6 | +import { LogOutputChannel, Uri } from 'vscode'; |
| 7 | +import { EnvironmentManager, PythonEnvironment } from '../../../api'; |
| 8 | +import { InlineScriptEnvManager } from '../../../managers/builtin/inlineScriptEnvManager'; |
| 9 | + |
| 10 | +function makeFakeLog(): LogOutputChannel { |
| 11 | + return sinon.createStubInstance( |
| 12 | + class { |
| 13 | + info() {} |
| 14 | + warn() {} |
| 15 | + error() {} |
| 16 | + debug() {} |
| 17 | + trace() {} |
| 18 | + show() {} |
| 19 | + dispose() {} |
| 20 | + append() {} |
| 21 | + appendLine() {} |
| 22 | + replace() {} |
| 23 | + clear() {} |
| 24 | + hide() {} |
| 25 | + }, |
| 26 | + ) as unknown as LogOutputChannel; |
| 27 | +} |
| 28 | + |
| 29 | +function makeEnv(): PythonEnvironment { |
| 30 | + return { |
| 31 | + envId: { id: 'fake', managerId: 'ms-python.python:inline-script' }, |
| 32 | + name: 'fake', |
| 33 | + displayName: 'fake', |
| 34 | + displayPath: '/fake', |
| 35 | + version: '3.12.0', |
| 36 | + environmentPath: Uri.file('/fake'), |
| 37 | + execInfo: { run: { executable: '/fake' } }, |
| 38 | + sysPrefix: '/fake', |
| 39 | + }; |
| 40 | +} |
| 41 | + |
| 42 | +suite('InlineScriptEnvManager (skeleton)', () => { |
| 43 | + let mgr: InlineScriptEnvManager; |
| 44 | + |
| 45 | + setup(() => { |
| 46 | + mgr = new InlineScriptEnvManager(makeFakeLog()); |
| 47 | + }); |
| 48 | + |
| 49 | + teardown(() => { |
| 50 | + mgr.dispose(); |
| 51 | + sinon.restore(); |
| 52 | + }); |
| 53 | + |
| 54 | + suite('static metadata', () => { |
| 55 | + test('name is "inline-script"', () => { |
| 56 | + assert.strictEqual(mgr.name, 'inline-script'); |
| 57 | + }); |
| 58 | + |
| 59 | + test('displayName is set (for the picker section header)', () => { |
| 60 | + assert.ok(mgr.displayName); |
| 61 | + assert.ok(mgr.displayName.length > 0); |
| 62 | + }); |
| 63 | + |
| 64 | + test('preferredPackageManagerId is the standard pip manager id', () => { |
| 65 | + assert.strictEqual(mgr.preferredPackageManagerId, 'ms-python.python:pip'); |
| 66 | + }); |
| 67 | + |
| 68 | + test('iconPath is defined (renders in the picker)', () => { |
| 69 | + assert.ok(mgr.iconPath); |
| 70 | + }); |
| 71 | + |
| 72 | + test('tooltip is defined (shown on hover in the picker)', () => { |
| 73 | + assert.ok(mgr.tooltip); |
| 74 | + }); |
| 75 | + }); |
| 76 | + |
| 77 | + suite('skeleton method behavior', () => { |
| 78 | + test('getEnvironments("all") returns []', async () => { |
| 79 | + assert.deepStrictEqual(await mgr.getEnvironments('all'), []); |
| 80 | + }); |
| 81 | + |
| 82 | + test('getEnvironments("global") returns []', async () => { |
| 83 | + assert.deepStrictEqual(await mgr.getEnvironments('global'), []); |
| 84 | + }); |
| 85 | + |
| 86 | + test('getEnvironments(Uri) returns []', async () => { |
| 87 | + assert.deepStrictEqual(await mgr.getEnvironments(Uri.file('/tmp/script.py')), []); |
| 88 | + }); |
| 89 | + |
| 90 | + test('get(undefined) returns undefined', async () => { |
| 91 | + assert.strictEqual(await mgr.get(undefined), undefined); |
| 92 | + }); |
| 93 | + |
| 94 | + test('get(Uri) returns undefined', async () => { |
| 95 | + assert.strictEqual(await mgr.get(Uri.file('/tmp/script.py')), undefined); |
| 96 | + }); |
| 97 | + |
| 98 | + test('set(scope, env) is a no-op and does not throw', async () => { |
| 99 | + await assert.doesNotReject(mgr.set(Uri.file('/tmp/script.py'), makeEnv())); |
| 100 | + await assert.doesNotReject(mgr.set(undefined, undefined)); |
| 101 | + }); |
| 102 | + |
| 103 | + test('refresh(scope) is a no-op and does not throw', async () => { |
| 104 | + await assert.doesNotReject(mgr.refresh(undefined)); |
| 105 | + await assert.doesNotReject(mgr.refresh(Uri.file('/tmp/script.py'))); |
| 106 | + }); |
| 107 | + |
| 108 | + test('resolve(Uri) returns undefined', async () => { |
| 109 | + assert.strictEqual(await mgr.resolve(Uri.file('/tmp/script.py')), undefined); |
| 110 | + }); |
| 111 | + |
| 112 | + test('does not implement optional create / remove / quickCreateConfig', () => { |
| 113 | + // Cast via the interface to probe optional methods (the concrete class type doesn't declare them). |
| 114 | + const asInterface: EnvironmentManager = mgr; |
| 115 | + assert.strictEqual(asInterface.create, undefined); |
| 116 | + assert.strictEqual(asInterface.remove, undefined); |
| 117 | + assert.strictEqual(asInterface.quickCreateConfig, undefined); |
| 118 | + }); |
| 119 | + }); |
| 120 | + |
| 121 | + suite('events', () => { |
| 122 | + test('onDidChangeEnvironments is exposed and subscribable', () => { |
| 123 | + const disposable = mgr.onDidChangeEnvironments(() => undefined); |
| 124 | + assert.ok(disposable); |
| 125 | + disposable.dispose(); |
| 126 | + }); |
| 127 | + |
| 128 | + test('onDidChangeEnvironment is exposed and subscribable', () => { |
| 129 | + const disposable = mgr.onDidChangeEnvironment(() => undefined); |
| 130 | + assert.ok(disposable); |
| 131 | + disposable.dispose(); |
| 132 | + }); |
| 133 | + |
| 134 | + test('skeleton methods do not fire any events', async () => { |
| 135 | + const envsListener = sinon.spy(); |
| 136 | + const envListener = sinon.spy(); |
| 137 | + mgr.onDidChangeEnvironments(envsListener); |
| 138 | + mgr.onDidChangeEnvironment(envListener); |
| 139 | + |
| 140 | + await mgr.getEnvironments('all'); |
| 141 | + await mgr.get(undefined); |
| 142 | + await mgr.set(Uri.file('/tmp/script.py'), makeEnv()); |
| 143 | + await mgr.refresh(undefined); |
| 144 | + await mgr.resolve(Uri.file('/tmp/script.py')); |
| 145 | + |
| 146 | + assert.strictEqual(envsListener.callCount, 0, 'getEnvironments/refresh must not fire envs event'); |
| 147 | + assert.strictEqual(envListener.callCount, 0, 'set must not fire env event in the skeleton'); |
| 148 | + }); |
| 149 | + }); |
| 150 | + |
| 151 | + suite('disposal', () => { |
| 152 | + test('dispose() does not throw', () => { |
| 153 | + assert.doesNotThrow(() => mgr.dispose()); |
| 154 | + }); |
| 155 | + |
| 156 | + test('dispose() is idempotent', () => { |
| 157 | + mgr.dispose(); |
| 158 | + assert.doesNotThrow(() => mgr.dispose()); |
| 159 | + }); |
| 160 | + }); |
| 161 | +}); |
0 commit comments