Skip to content

Commit e585a15

Browse files
authored
Update logic used to parse the args passed into the test frameworks (#1917)
* Refactor unit test discovery * test * Unit tests * Update logic used to parse the args passed into the test frameworks * fix tests * Fix tests * Fix path to test files * Fix tests * Fix more tests * Fix pytest tests * Fix tests * More fixes * Bug fix * fix code review comments * add missing awaits * Create tests for filtering of arguments
1 parent 23da67a commit e585a15

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2281
-562
lines changed

news/2 Fixes/1070.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improvements to the logic used to parse the arguments passed into the test frameworks.

package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,6 +1955,7 @@
19551955
"@types/semver": "^5.5.0",
19561956
"@types/shortid": "^0.0.29",
19571957
"@types/sinon": "^4.3.0",
1958+
"@types/tmp": "0.0.33",
19581959
"@types/untildify": "^3.0.0",
19591960
"@types/uuid": "^3.4.3",
19601961
"@types/winreg": "^1.2.30",

src/client/activation/downloader.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as request from 'request';
77
import * as requestProgress from 'request-progress';
88
import { OutputChannel, ProgressLocation, window } from 'vscode';
99
import { STANDARD_OUTPUT_CHANNEL } from '../common/constants';
10-
import { createDeferred, createTemporaryFile } from '../common/helpers';
10+
import { createDeferred } from '../common/helpers';
1111
import { IFileSystem, IPlatformService } from '../common/platform/types';
1212
import { IExtensionContext, IOutputChannel } from '../common/types';
1313
import { IServiceContainer } from '../ioc/types';
@@ -58,14 +58,14 @@ export class AnalysisEngineDownloader {
5858
private async downloadFile(location: string, fileName: string, title: string): Promise<string> {
5959
const uri = `${location}/${fileName}`;
6060
this.output.append(`Downloading ${uri}... `);
61-
const tempFile = await createTemporaryFile(downloadFileExtension);
61+
const tempFile = await this.fs.createTemporaryFile(downloadFileExtension);
6262

6363
const deferred = createDeferred();
6464
const fileStream = fileSystem.createWriteStream(tempFile.filePath);
6565
fileStream.on('finish', () => {
6666
fileStream.close();
6767
}).on('error', (err) => {
68-
tempFile.cleanupCallback();
68+
tempFile.dispose();
6969
deferred.reject(err);
7070
});
7171

src/client/application/diagnostics/applicationDiagnostics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class ApplicationDiagnostics implements IApplicationDiagnostics {
2020
const diagnostics = await envHealthCheck.diagnose();
2121
this.log(diagnostics);
2222
if (diagnostics.length > 0) {
23-
envHealthCheck.handle(diagnostics);
23+
await envHealthCheck.handle(diagnostics);
2424
}
2525
}
2626
private log(diagnostics: IDiagnostic[]): void {

src/client/application/diagnostics/checks/envPathVariable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export class EnvironmentPathVariableDiagnosticsService extends BaseDiagnosticsSe
5454
return;
5555
}
5656
const diagnostic = diagnostics[0];
57-
if (this.filterService.shouldIgnoreDiagnostic(diagnostic.code)) {
57+
if (await this.filterService.shouldIgnoreDiagnostic(diagnostic.code)) {
5858
return;
5959
}
6060
const commandFactory = this.serviceContainer.get<IDiagnosticsCommandFactory>(IDiagnosticsCommandFactory);

src/client/common/application/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ export interface IDocumentManager {
407407
showTextDocument(uri: Uri, options?: TextDocumentShowOptions): Thenable<TextEditor>;
408408
}
409409

410-
export const IWorkspaceService = Symbol('IWorkspace');
410+
export const IWorkspaceService = Symbol('IWorkspaceService');
411411

412412
export interface IWorkspaceService {
413413
/**

src/client/common/platform/fileSystem.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import * as fs from 'fs-extra';
77
import * as glob from 'glob';
88
import { inject, injectable } from 'inversify';
99
import * as path from 'path';
10+
import * as tmp from 'tmp';
1011
import { createDeferred } from '../helpers';
11-
import { IFileSystem, IPlatformService } from './types';
12+
import { IFileSystem, IPlatformService, TemporaryFile } from './types';
1213

1314
@injectable()
1415
export class FileSystem implements IFileSystem {
@@ -141,4 +142,15 @@ export class FileSystem implements IFileSystem {
141142
});
142143
});
143144
}
145+
public createTemporaryFile(extension: string): Promise<TemporaryFile> {
146+
return new Promise<TemporaryFile>((resolve, reject) => {
147+
tmp.file({ postfix: extension }, (err, tmpFile, _, cleanupCallback) => {
148+
if (err) {
149+
return reject(err);
150+
}
151+
resolve({ filePath: tmpFile, dispose: cleanupCallback });
152+
});
153+
});
154+
155+
}
144156
}

src/client/common/platform/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33

44
import * as fs from 'fs';
5+
import { Disposable } from 'vscode';
56

67
export enum Architecture {
78
Unknown = 1,
@@ -28,6 +29,8 @@ export interface IPlatformService {
2829
virtualEnvBinName: 'bin' | 'scripts';
2930
}
3031

32+
export type TemporaryFile = { filePath: string } & Disposable;
33+
3134
export const IFileSystem = Symbol('IFileSystem');
3235
export interface IFileSystem {
3336
directorySeparatorChar: string;
@@ -48,4 +51,5 @@ export interface IFileSystem {
4851
deleteFile(filename: string): Promise<void>;
4952
getFileHash(filePath: string): Promise<string | undefined>;
5053
search(globPattern: string): Promise<string[]>;
54+
createTemporaryFile(extension: string): Promise<TemporaryFile>;
5155
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
import { inject, injectable } from 'inversify';
7+
import { ILogger } from '../../common/types';
8+
import { IServiceContainer } from '../../ioc/types';
9+
import { IArgumentsHelper } from '../types';
10+
11+
@injectable()
12+
export class ArgumentsHelper implements IArgumentsHelper {
13+
private readonly logger: ILogger;
14+
constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) {
15+
this.logger = serviceContainer.get<ILogger>(ILogger);
16+
}
17+
public getOptionValues(args: string[], option: string): string | string[] | undefined {
18+
const values: string[] = [];
19+
let returnNextValue = false;
20+
for (const arg of args) {
21+
if (returnNextValue) {
22+
values.push(arg);
23+
returnNextValue = false;
24+
continue;
25+
}
26+
if (arg.startsWith(`${option}=`)) {
27+
values.push(arg.substring(`${option}=`.length));
28+
continue;
29+
}
30+
if (arg === option) {
31+
returnNextValue = true;
32+
}
33+
}
34+
switch (values.length) {
35+
case 0: {
36+
return;
37+
}
38+
case 1: {
39+
return values[0];
40+
}
41+
default: {
42+
return values;
43+
}
44+
}
45+
}
46+
public getPositionalArguments(args: string[], optionsWithArguments: string[] = [], optionsWithoutArguments: string[] = []): string[] {
47+
let lastIndexOfOption = -1;
48+
args.forEach((arg, index) => {
49+
if (optionsWithoutArguments.indexOf(arg) !== -1) {
50+
lastIndexOfOption = index;
51+
return;
52+
} else if (optionsWithArguments.indexOf(arg) !== -1) {
53+
// Cuz the next item is the value.
54+
lastIndexOfOption = index + 1;
55+
} else if (optionsWithArguments.findIndex(item => arg.startsWith(`${item}=`)) !== -1) {
56+
lastIndexOfOption = index;
57+
return;
58+
} else if (arg.startsWith('-')) {
59+
// Ok this is an unknown option, lets treat this as one without values.
60+
this.logger.logWarning(`Unknown command line option passed into args parser for tests '${arg}'. Please report on https://github.com/Microsoft/vscode-python/issues/new`);
61+
lastIndexOfOption = index;
62+
return;
63+
} else if (args.indexOf('=') > 0) {
64+
// Ok this is an unknown option with a value
65+
this.logger.logWarning(`Unknown command line option passed into args parser for tests '${arg}'. Please report on https://github.com/Microsoft/vscode-python/issues/new`);
66+
lastIndexOfOption = index;
67+
}
68+
});
69+
return args.slice(lastIndexOfOption + 1);
70+
}
71+
public filterArguments(args: string[], optionsWithArguments: string[] = [], optionsWithoutArguments: string[] = []): string[] {
72+
let ignoreIndex = -1;
73+
return args.filter((arg, index) => {
74+
if (ignoreIndex === index) {
75+
return false;
76+
}
77+
// Options can use willd cards (with trailing '*')
78+
if (optionsWithoutArguments.indexOf(arg) >= 0 ||
79+
optionsWithoutArguments.filter(option => option.endsWith('*') && arg.startsWith(option.slice(0, -1))).length > 0) {
80+
return false;
81+
}
82+
// Ignore args that match exactly.
83+
if (optionsWithArguments.indexOf(arg) >= 0) {
84+
ignoreIndex = index + 1;
85+
return false;
86+
}
87+
// Ignore args that match exactly with wild cards & do not have inline values.
88+
if (optionsWithArguments.filter(option => arg.startsWith(`${option}=`)).length > 0) {
89+
return false;
90+
}
91+
// Ignore args that match a wild card (ending with *) and no ineline values.
92+
// Eg. arg='--log-cli-level' and optionsArguments=['--log-*']
93+
if (arg.indexOf('=') === -1 && optionsWithoutArguments.filter(option => option.endsWith('*') && arg.startsWith(option.slice(0, -1))).length > 0) {
94+
ignoreIndex = index + 1;
95+
return false;
96+
}
97+
// Ignore args that match a wild card (ending with *) and have ineline values.
98+
// Eg. arg='--log-cli-level=XYZ' and optionsArguments=['--log-*']
99+
if (arg.indexOf('=') >= 0 && optionsWithoutArguments.filter(option => option.endsWith('*') && arg.startsWith(option.slice(0, -1))).length > 0) {
100+
return false;
101+
}
102+
return true;
103+
});
104+
}
105+
}

0 commit comments

Comments
 (0)