forked from microsoft/vscode-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfiguration.ts
More file actions
110 lines (106 loc) · 5.8 KB
/
configuration.ts
File metadata and controls
110 lines (106 loc) · 5.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
'use strict';
import { inject, injectable } from 'inversify';
import { OutputChannel, Uri } from 'vscode';
import { IApplicationShell, IWorkspaceService } from '../common/application/types';
import { IConfigurationService, IInstaller, IOutputChannel, Product } from '../common/types';
import { IServiceContainer } from '../ioc/types';
import { TEST_OUTPUT_CHANNEL } from './common/constants';
import { UnitTestProduct } from './common/types';
import { ITestConfigurationManagerFactory, IUnitTestConfigurationService } from './types';
@injectable()
export class UnitTestConfigurationService implements IUnitTestConfigurationService {
private readonly configurationService: IConfigurationService;
private readonly appShell: IApplicationShell;
private readonly installer: IInstaller;
private readonly outputChannel: OutputChannel;
private readonly workspaceService: IWorkspaceService;
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {
this.configurationService = serviceContainer.get<IConfigurationService>(IConfigurationService);
this.appShell = serviceContainer.get<IApplicationShell>(IApplicationShell);
this.installer = serviceContainer.get<IInstaller>(IInstaller);
this.outputChannel = serviceContainer.get<OutputChannel>(IOutputChannel, TEST_OUTPUT_CHANNEL);
this.workspaceService = serviceContainer.get<IWorkspaceService>(IWorkspaceService);
}
public async displayTestFrameworkError(wkspace: Uri): Promise<void> {
const settings = this.configurationService.getSettings(wkspace);
let enabledCount = settings.unitTest.pyTestEnabled ? 1 : 0;
enabledCount += settings.unitTest.nosetestsEnabled ? 1 : 0;
enabledCount += settings.unitTest.unittestEnabled ? 1 : 0;
if (enabledCount > 1) {
return this.promptToEnableAndConfigureTestFramework(wkspace, this.installer, this.outputChannel, 'Enable only one of the test frameworks (unittest, pytest or nosetest).', true);
} else {
const option = 'Enable and configure a Test Framework';
const item = await this.appShell.showInformationMessage('No test framework configured (unittest, pytest or nosetest)', option);
if (item === option) {
return this.promptToEnableAndConfigureTestFramework(wkspace, this.installer, this.outputChannel);
}
return Promise.reject(null);
}
}
public async selectTestRunner(placeHolderMessage: string): Promise<UnitTestProduct | undefined> {
const items = [{
label: 'unittest',
product: Product.unittest,
description: 'Standard Python test framework',
detail: 'https://docs.python.org/3/library/unittest.html'
},
{
label: 'pytest',
product: Product.pytest,
description: 'Can run unittest (including trial) and nose test suites out of the box',
// tslint:disable-next-line:no-http-string
detail: 'http://docs.pytest.org/'
},
{
label: 'nose',
product: Product.nosetest,
description: 'nose framework',
detail: 'https://nose.readthedocs.io/'
}];
const options = {
matchOnDescription: true,
matchOnDetail: true,
placeHolder: placeHolderMessage
};
const selectedTestRunner = await this.appShell.showQuickPick(items, options);
// tslint:disable-next-line:prefer-type-cast
return selectedTestRunner ? selectedTestRunner.product as UnitTestProduct : undefined;
}
public enableTest(wkspace: Uri, product: UnitTestProduct) {
const factory = this.serviceContainer.get<ITestConfigurationManagerFactory>(ITestConfigurationManagerFactory);
const configMgr = factory.create(wkspace, product);
const pythonConfig = this.workspaceService.getConfiguration('python', wkspace);
if (pythonConfig.get<boolean>('unitTest.promptToConfigure')) {
return configMgr.enable();
}
return pythonConfig.update('unitTest.promptToConfigure', undefined).then(() => {
return configMgr.enable();
}, reason => {
return configMgr.enable().then(() => Promise.reject(reason));
});
}
private async promptToEnableAndConfigureTestFramework(wkspace: Uri, installer: IInstaller, outputChannel: OutputChannel, messageToDisplay: string = 'Select a test framework/tool to enable', enableOnly: boolean = false) {
const selectedTestRunner = await this.selectTestRunner(messageToDisplay);
if (typeof selectedTestRunner !== 'number') {
return Promise.reject(null);
}
const factory = this.serviceContainer.get<ITestConfigurationManagerFactory>(ITestConfigurationManagerFactory);
const configMgr = factory.create(wkspace, selectedTestRunner);
if (enableOnly) {
// Ensure others are disabled
[Product.unittest, Product.pytest, Product.nosetest]
.filter(prod => selectedTestRunner !== prod)
.forEach(prod => {
factory.create(wkspace, prod).disable()
.catch(ex => console.error('Python Extension: createTestConfigurationManager.disable', ex));
});
return configMgr.enable();
}
// Configure everything before enabling.
// Cuz we don't want the test engine (in main.ts file - tests get discovered when config changes are detected)
// to start discovering tests when tests haven't been configured properly.
return configMgr.configure(wkspace)
.then(() => this.enableTest(wkspace, selectedTestRunner))
.catch(reason => { return this.enableTest(wkspace, selectedTestRunner).then(() => Promise.reject(reason)); });
}
}