From 82a6aeef340fa1d694fa857e22d2cc834f0fc82a Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Sat, 4 Nov 2017 12:32:02 -0700 Subject: [PATCH 01/10] Unit Test Refactor Move unit tests into their own folder. Prepare scripts for unit + integration tests. --- .vscode/launch.json | 9 ++++--- package.json | 12 ++++++++- test/sanity.test.ts | 26 ------------------- test/{ => unitTests}/assets.test.ts | 7 +++--- test/{ => unitTests}/common.test.ts | 4 ++- test/unitTests/index.ts | 29 ++++++++++++++++++++++ test/{ => unitTests}/json.test.ts | 2 +- test/{ => unitTests}/platform.test.ts | 2 +- test/{ => unitTests}/processPicker.test.ts | 23 ++++++++++------- 9 files changed, 69 insertions(+), 45 deletions(-) delete mode 100644 test/sanity.test.ts rename test/{ => unitTests}/assets.test.ts (99%) rename test/{ => unitTests}/common.test.ts (97%) create mode 100644 test/unitTests/index.ts rename test/{ => unitTests}/json.test.ts (99%) rename test/{ => unitTests}/platform.test.ts (97%) rename test/{ => unitTests}/processPicker.test.ts (95%) diff --git a/.vscode/launch.json b/.vscode/launch.json index b89fcb9578..804dddc499 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,11 +16,14 @@ ] }, { - "name": "Launch Tests", + "name": "Launch Unit Tests", "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], + "args": [ + "--extensionDevelopmentPath=${workspaceRoot}", + "--extensionTestsPath=${workspaceRoot}/out/test/unitTests" + ], "stopOnEntry": false, "sourceMaps": true, "outFiles": [ @@ -28,4 +31,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/package.json b/package.json index 959705d77a..5e522b1af9 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,11 @@ "vscode:prepublish": "tsc -p ./", "compile": "tsc -p ./ && gulp tslint", "watch": "tsc -watch -p ./", - "test": "node ./node_modules/vscode/bin/test", + "test": "npm-run-all test:unit test:integration", + "test:unit": "cross-env CODE_TESTS_PATH=./out/test/unitTests npm run test:runInVsCode", + "test:integration": "npm-run-all test:integration:*", + "test:runSuiteInVsCode": "cross-env CODE_TESTS_PATH=./out/test/integrationTests CODE_TESTS_WORKSPACE=./test/integrationTests/testAssets/$OSVC_SUITE npm run test:runInVsCode", + "test:runInVsCode": "node ./test/runVsCodeTestsWithAbsolutePaths.js", "postinstall": "node ./node_modules/vscode/bin/install" }, "dependencies": { @@ -46,18 +50,24 @@ }, "devDependencies": { "@types/chai": "^3.4.34", + "@types/chai-arrays": "^1.0.2", "@types/fs-extra": "4.0.3", "@types/mkdirp": "^0.3.29", "@types/mocha": "^2.2.32", "@types/node": "^6.0.40", "@types/semver": "^5.3.30", "@types/tmp": "0.0.32", + "async-file": "^2.0.2", "chai": "^3.5.0", + "chai-arrays": "^2.0.0", + "chai-fs": "^1.0.0", + "cross-env": "^5.1.1", "del": "^2.0.2", "gulp": "^3.9.1", "gulp-mocha": "^2.1.3", "gulp-tslint": "^4.3.0", "mocha": "^2.3.3", + "npm-run-all": "^4.1.1", "plist": "^2.0.1", "tslint": "^3.15.1", "tslint-microsoft-contrib": "^2.0.12", diff --git a/test/sanity.test.ts b/test/sanity.test.ts deleted file mode 100644 index ac1fbb53fc..0000000000 --- a/test/sanity.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// -// Note: This example test is leveraging the Mocha test framework. -// Please refer to their documentation on https://mochajs.org/ for help. -// - -// The module 'assert' provides assertion methods from node -import * as assert from 'assert'; - -// You can import and use all API from the 'vscode' module -// as well as import your extension to test it -import * as vscode from 'vscode'; -import * as myExtension from '../src/main'; - -suite("Sanity Tests", () => { - test("Boolean checks", () => { - assert.equal(true, true, "true is not true"); - assert.notEqual(true, false, "true is false"); - assert.equal(false, false, "false is not false"); - assert.notEqual(false, true, "false is true"); - }); -}); \ No newline at end of file diff --git a/test/assets.test.ts b/test/unitTests/assets.test.ts similarity index 99% rename from test/assets.test.ts rename to test/unitTests/assets.test.ts index fd3effd2ae..606f9b5d15 100644 --- a/test/assets.test.ts +++ b/test/unitTests/assets.test.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { should } from 'chai'; import * as path from 'path'; -import * as protocol from '../src/omnisharp/protocol'; -import { AssetGenerator } from '../src/assets'; +import * as protocol from '../../src/omnisharp/protocol'; + +import { AssetGenerator } from '../../src/assets'; import { parse } from 'jsonc-parser'; +import { should } from 'chai'; suite("Asset generation: project.json", () => { suiteSetup(() => should()); diff --git a/test/common.test.ts b/test/unitTests/common.test.ts similarity index 97% rename from test/common.test.ts rename to test/unitTests/common.test.ts index 483586fc84..fbfe309e8c 100644 --- a/test/common.test.ts +++ b/test/unitTests/common.test.ts @@ -4,8 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'path'; + +import { buildPromiseChain, isSubfolderOf, safeLength, sum } from '../../src/common'; + import { should } from 'chai'; -import { buildPromiseChain, safeLength, sum, isSubfolderOf } from '../src/common'; suite("Common", () => { suiteSetup(() => should()); diff --git a/test/unitTests/index.ts b/test/unitTests/index.ts new file mode 100644 index 0000000000..cda6a4004a --- /dev/null +++ b/test/unitTests/index.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// +// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING +// +// This file is providing the test runner to use when running extension tests. +// By default the test runner in use is Mocha based. +// +// You can provide your own test runner if you want to override it by exporting +// a function run(testRoot: string, clb: (error:Error) => void) that the extension +// host can call to run the tests. The test runner is expected to use console.log +// to report the results back to the caller. When the tests are finished, return +// a possible error to the callback or null if none. + +var testRunner = require('vscode/lib/testrunner'); + +// You can directly control Mocha options by uncommenting the following lines +// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info + +testRunner.configure({ + timeout: 10000, + ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) + useColors: true // colored output from test results +}); + +module.exports = testRunner; \ No newline at end of file diff --git a/test/json.test.ts b/test/unitTests/json.test.ts similarity index 99% rename from test/json.test.ts rename to test/unitTests/json.test.ts index 08b34ec776..7cb9d88847 100644 --- a/test/json.test.ts +++ b/test/unitTests/json.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { should } from 'chai'; -import { tolerantParse } from '../src/json'; +import { tolerantParse } from '../../src/json'; suite("JSON", () => { suiteSetup(() => should()); diff --git a/test/platform.test.ts b/test/unitTests/platform.test.ts similarity index 97% rename from test/platform.test.ts rename to test/unitTests/platform.test.ts index a5499f75d3..83aed13e2f 100644 --- a/test/platform.test.ts +++ b/test/unitTests/platform.test.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { LinuxDistribution } from '../../src/platform'; import { should } from 'chai'; -import { LinuxDistribution, PlatformInformation } from '../src/platform'; suite("Platform", () => { suiteSetup(() => should()); diff --git a/test/processPicker.test.ts b/test/unitTests/processPicker.test.ts similarity index 95% rename from test/processPicker.test.ts rename to test/unitTests/processPicker.test.ts index cfbcaf5d33..736536b16e 100644 --- a/test/processPicker.test.ts +++ b/test/unitTests/processPicker.test.ts @@ -1,5 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { RemoteAttachPicker } from '../../src/features/processPicker'; import { should } from 'chai'; -import { RemoteAttachPicker } from '../src/features/processPicker'; suite("Remote Process Picker: Validate quoting arguments.", () => { suiteSetup(() => should()); @@ -159,7 +164,7 @@ function GetWindowsWSLLaunchJSONWithArrayArgs() { pipeCwd: "${workspaceFolder}", pipeProgram: "C:\\System32\\bash.exe", pipeArgs: ["-c"] - } + }; } function GetWindowsWSLLaunchJSONWithArrayArgsAndDebuggerCommand() { @@ -167,7 +172,7 @@ function GetWindowsWSLLaunchJSONWithArrayArgsAndDebuggerCommand() { pipeCwd: "${workspaceFolder}", pipeProgram: "C:\\System32\\bash.exe", pipeArgs: ["-c", "${debuggerCommand}", "--", "ignored"] - } + }; } function GetWindowsWSLLaunchJSONWithStringArgs() { @@ -175,7 +180,7 @@ function GetWindowsWSLLaunchJSONWithStringArgs() { pipeCwd: "${workspaceFolder}", pipeProgram: "C:\\System32\\bash.exe", pipeArgs: "-c" - } + }; } function GetWindowsWSLLaunchJSONWithStringArgsAndDebuggerCommand() { @@ -183,7 +188,7 @@ function GetWindowsWSLLaunchJSONWithStringArgsAndDebuggerCommand() { pipeCwd: "${workspaceFolder}", pipeProgram: "C:\\System32\\bash.exe", pipeArgs: "-c ${debuggerCommand} -- ignored" - } + }; } function GetWindowsDockerLaunchJSONWithArrayArgs() { @@ -192,7 +197,7 @@ function GetWindowsDockerLaunchJSONWithArrayArgs() { pipeProgram: "docker", pipeArgs: ["-i", "exec", "1234567"], quoteArgs: false - } + }; }; function GetWindowsDockerLaunchJSONWithStringArgsAndDebuggerCommand() { @@ -201,7 +206,7 @@ function GetWindowsDockerLaunchJSONWithStringArgsAndDebuggerCommand() { pipeProgram: "docker", pipeArgs: "-i exec 1234567 ${debuggerCommand}", quoteArgs: false - } + }; } function GetLinuxLaunchJSONWithArrayArgs() { @@ -210,7 +215,7 @@ function GetLinuxLaunchJSONWithArrayArgs() { pipeProgram: "/usr/bin/shared/dotnet", pipeArgs: ["bin/framework/myprogram.dll", "argument with spaces"], quoteArg: true - } + }; } function GetOSSpecificJSON() { @@ -229,5 +234,5 @@ function GetOSSpecificJSON() { linux: { pipeProgram: "Linux pipeProgram", } - } + }; } \ No newline at end of file From 77e74f3b35a8f7e38019376130d43392863b3ddb Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Sat, 4 Nov 2017 12:36:20 -0700 Subject: [PATCH 02/10] Add integration test infra --- .gitignore | 3 + .travis.yml | 3 + test/{ => integrationTests}/index.ts | 1 + .../testAssets/testAssetWorkspace.ts | 20 ++++++ .../integrationTests/testAssets/testAssets.ts | 61 +++++++++++++++++++ test/runVsCodeTestsWithAbsolutePaths.js | 15 +++++ 6 files changed, 103 insertions(+) rename test/{ => integrationTests}/index.ts (99%) create mode 100644 test/integrationTests/testAssets/testAssetWorkspace.ts create mode 100644 test/integrationTests/testAssets/testAssets.ts create mode 100644 test/runVsCodeTestsWithAbsolutePaths.js diff --git a/.gitignore b/.gitignore index 8229cf2d9f..a2bb29b96d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ out install.* *.vsix + +obj/ +bin/ diff --git a/.travis.yml b/.travis.yml index ff571682bd..00d04dd15b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,12 @@ addons: apt: sources: - ubuntu-toolchain-r-test + - sourceline: 'deb https://packages.microsoft.com/repos/microsoft-ubuntu-trusty-prod trusty main' + key_url: 'https://packages.microsoft.com/keys/microsoft.asc' packages: - g++-4.9 - libsecret-1-dev + - dotnet-sdk-2.0.2 install: - npm install diff --git a/test/index.ts b/test/integrationTests/index.ts similarity index 99% rename from test/index.ts rename to test/integrationTests/index.ts index 2bf0a6fde4..cda6a4004a 100644 --- a/test/index.ts +++ b/test/integrationTests/index.ts @@ -19,6 +19,7 @@ var testRunner = require('vscode/lib/testrunner'); // You can directly control Mocha options by uncommenting the following lines // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info + testRunner.configure({ timeout: 10000, ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) diff --git a/test/integrationTests/testAssets/testAssetWorkspace.ts b/test/integrationTests/testAssets/testAssetWorkspace.ts new file mode 100644 index 0000000000..8997c07e23 --- /dev/null +++ b/test/integrationTests/testAssets/testAssetWorkspace.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'path'; +import * as vscode from 'vscode'; + +import {ITestAssetWorkspace, TestAssetWorkspace} from './testAssets'; + +const testAssetWorkspaces: { [x: string]: ITestAssetWorkspace } = { +}; + +const workspaceName = vscode.workspace.rootPath + .split(path.sep) + .pop(); + +const activeTestAssetWorkspace = new TestAssetWorkspace(testAssetWorkspaces[workspaceName]); + +export default activeTestAssetWorkspace; \ No newline at end of file diff --git a/test/integrationTests/testAssets/testAssets.ts b/test/integrationTests/testAssets/testAssets.ts new file mode 100644 index 0000000000..63da6a9f86 --- /dev/null +++ b/test/integrationTests/testAssets/testAssets.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as fs from 'async-file'; +import * as path from 'path'; +import * as vscode from 'vscode'; + +export class TestAssetProject { + constructor(project: ITestAssetProject) { + this.relativePath = project.relativePath; + } + + relativePath: string; + + get projectDirectoryPath(): string { + return path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, + this.relativePath); + } + + get binDirectoryPath(): string { + return path.join(this.projectDirectoryPath, 'bin'); + } + + get objDirectoryPath(): string { + return path.join(this.projectDirectoryPath, 'obj'); + } + + async deleteBuildArtifacts(): Promise { + await fs.rimraf(this.binDirectoryPath); + await fs.rimraf(this.objDirectoryPath); + } +} + +export class TestAssetWorkspace { + constructor(workspace: ITestAssetWorkspace) { + this.projects = workspace.projects.map( + w => new TestAssetProject(w) + ); + + this.description = workspace.description; + } + + async deleteBuildArtifacts(): Promise { + this.projects.forEach(async p => await p.deleteBuildArtifacts()); + } + + description: string; + + projects: TestAssetProject []; +} + +export interface ITestAssetProject { + relativePath: string; +} + +export interface ITestAssetWorkspace { + description: string; + projects: ITestAssetProject[]; +} \ No newline at end of file diff --git a/test/runVsCodeTestsWithAbsolutePaths.js b/test/runVsCodeTestsWithAbsolutePaths.js new file mode 100644 index 0000000000..a4a5176cbc --- /dev/null +++ b/test/runVsCodeTestsWithAbsolutePaths.js @@ -0,0 +1,15 @@ +#!/usr/bin/env node + +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +path=require('path'); + +if (process.env.CODE_TESTS_PATH + && process.env.CODE_TESTS_PATH.startsWith('.')){ + process.env.CODE_TESTS_PATH = path.join(process.cwd(), process.env.CODE_TESTS_PATH.substr(2)); +} + +require(path.resolve(__dirname, '../node_modules/vscode/bin/test')); \ No newline at end of file From 571e68be845af67a2abea370aed57271236795d7 Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Sat, 4 Nov 2017 16:05:47 -0700 Subject: [PATCH 03/10] Add tslint rules and clean up some source files --- src/configurationProvider.ts | 12 ++++--- .../definitionMetadataDocumentProvider.ts | 8 ++++- src/omnisharp/extension.ts | 33 ++++++++++--------- src/tools/GenerateOptionsSchema.ts | 5 +++ src/tools/UpdatePackageDependencies.ts | 6 ++++ tslint.json | 4 ++- 6 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/configurationProvider.ts b/src/configurationProvider.ts index d4dcdea569..34edf902e7 100644 --- a/src/configurationProvider.ts +++ b/src/configurationProvider.ts @@ -3,15 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; import * as fs from 'fs-extra'; import * as path from 'path'; -import { parse } from 'jsonc-parser'; -import { OmniSharpServer } from './omnisharp/server'; import * as serverUtils from './omnisharp/utils'; +import * as vscode from 'vscode'; + +import { AssetGenerator, addTasksJsonIfNecessary, createAttachConfiguration, createLaunchConfiguration, createWebLaunchConfiguration } from './assets'; + +import { OmniSharpServer } from './omnisharp/server'; import { containsDotNetCoreProjects } from './omnisharp/protocol'; -import { AssetGenerator, addTasksJsonIfNecessary, createLaunchConfiguration, createAttachConfiguration, createWebLaunchConfiguration } from './assets'; import { isSubfolderOf } from './common'; +import { parse } from 'jsonc-parser'; export class CSharpConfigurationProvider implements vscode.DebugConfigurationProvider { private server: OmniSharpServer; @@ -101,7 +103,7 @@ export class CSharpConfigurationProvider implements vscode.DebugConfigurationPro /** * Try to add all missing attributes to the debug configuration being launched. */ - resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, token?: vscode.CancellationToken): vscode.ProviderResult { + resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, token?: vscode.CancellationToken): vscode.ProviderResult { // vsdbg does the error checking return config; } diff --git a/src/features/definitionMetadataDocumentProvider.ts b/src/features/definitionMetadataDocumentProvider.ts index f9a337da12..e4cb4545d9 100644 --- a/src/features/definitionMetadataDocumentProvider.ts +++ b/src/features/definitionMetadataDocumentProvider.ts @@ -1,4 +1,10 @@ -import { workspace, Uri, TextDocument, Disposable, TextDocumentContentProvider} from 'vscode'; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable, TextDocument, TextDocumentContentProvider, Uri, workspace } from 'vscode'; + import { MetadataResponse } from '../omnisharp/protocol'; export default class DefinitionMetadataDocumentProvider implements TextDocumentContentProvider, Disposable { diff --git a/src/omnisharp/extension.ts b/src/omnisharp/extension.ts index f415e637fb..99d148f600 100644 --- a/src/omnisharp/extension.ts +++ b/src/omnisharp/extension.ts @@ -3,34 +3,35 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as utils from './utils'; import * as vscode from 'vscode'; -import TelemetryReporter from 'vscode-extension-telemetry'; -import DefinitionProvider from '../features/definitionProvider'; -import ImplementationProvider from '../features/implementationProvider'; +import { AddAssetResult, addAssetsIfNecessary } from '../assets'; +import reportDiagnostics, { Advisor } from '../features/diagnosticsProvider'; +import { safeLength, sum } from '../common'; + +import { CSharpConfigurationProvider } from '../configurationProvider'; +import CodeActionProvider from '../features/codeActionProvider'; import CodeLensProvider from '../features/codeLensProvider'; +import CompletionItemProvider from '../features/completionItemProvider'; import DefinitionMetadataDocumentProvider from '../features/definitionMetadataDocumentProvider'; +import DefinitionProvider from '../features/definitionProvider'; import DocumentHighlightProvider from '../features/documentHighlightProvider'; import DocumentSymbolProvider from '../features/documentSymbolProvider'; -import CodeActionProvider from '../features/codeActionProvider'; -import ReferenceProvider from '../features/referenceProvider'; +import FormatProvider from '../features/formattingEditProvider'; import HoverProvider from '../features/hoverProvider'; +import ImplementationProvider from '../features/implementationProvider'; +import { OmniSharpServer } from './server'; +import { Options } from './options'; +import ReferenceProvider from '../features/referenceProvider'; import RenameProvider from '../features/renameProvider'; -import FormatProvider from '../features/formattingEditProvider'; -import CompletionItemProvider from '../features/completionItemProvider'; -import WorkspaceSymbolProvider from '../features/workspaceSymbolProvider'; -import reportDiagnostics, { Advisor } from '../features/diagnosticsProvider'; import SignatureHelpProvider from '../features/signatureHelpProvider'; +import TelemetryReporter from 'vscode-extension-telemetry'; import TestManager from '../features/dotnetTest'; -import registerCommands from '../features/commands'; +import WorkspaceSymbolProvider from '../features/workspaceSymbolProvider'; import forwardChanges from '../features/changeForwarding'; +import registerCommands from '../features/commands'; import reportStatus from '../features/status'; -import { OmniSharpServer } from './server'; -import { Options } from './options'; -import { addAssetsIfNecessary, AddAssetResult } from '../assets'; -import { sum, safeLength } from '../common'; -import * as utils from './utils'; -import { CSharpConfigurationProvider } from '../configurationProvider'; export function activate(context: vscode.ExtensionContext, reporter: TelemetryReporter, channel: vscode.OutputChannel) { const documentSelector: vscode.DocumentSelector = { diff --git a/src/tools/GenerateOptionsSchema.ts b/src/tools/GenerateOptionsSchema.ts index 54ff3bd26c..a14dedf993 100644 --- a/src/tools/GenerateOptionsSchema.ts +++ b/src/tools/GenerateOptionsSchema.ts @@ -1,3 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + import * as fs from 'fs'; import * as os from 'os'; diff --git a/src/tools/UpdatePackageDependencies.ts b/src/tools/UpdatePackageDependencies.ts index 6e973b0b4a..e0a69edfc3 100644 --- a/src/tools/UpdatePackageDependencies.ts +++ b/src/tools/UpdatePackageDependencies.ts @@ -1,5 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + import * as fs from 'fs'; import * as os from 'os'; + import { Package } from '../packages'; interface PackageJSONFile diff --git a/tslint.json b/tslint.json index 682162074d..a5115d4988 100644 --- a/tslint.json +++ b/tslint.json @@ -7,6 +7,8 @@ "no-var-keyword": true, "promise-must-complete": true, "curly": true, - "semicolon": true + "semicolon": true, + "indent": [true, "spaces", 4], + "file-header": [true, ".*"] } } \ No newline at end of file From 72b3fcffc535fa59aed01c8fa2549cb8d5e118f7 Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Sat, 4 Nov 2017 16:29:08 -0700 Subject: [PATCH 04/10] Add test asset: slnWithCsproj --- .vscode/launch.json | 16 +++++ package.json | 1 + .../slnWithCsproj/slnWithCsproj.sln | 68 +++++++++++++++++++ .../slnWithCsproj/src/app/Program.cs | 12 ++++ .../slnWithCsproj/src/app/app.csproj | 12 ++++ .../slnWithCsproj/src/lib/Class1.cs | 8 +++ .../slnWithCsproj/src/lib/lib.csproj | 7 ++ .../slnWithCsproj/test/UnitTest1.cs | 14 ++++ .../testAssets/slnWithCsproj/test/test.csproj | 15 ++++ 9 files changed, 153 insertions(+) create mode 100644 test/integrationTests/testAssets/slnWithCsproj/slnWithCsproj.sln create mode 100644 test/integrationTests/testAssets/slnWithCsproj/src/app/Program.cs create mode 100644 test/integrationTests/testAssets/slnWithCsproj/src/app/app.csproj create mode 100644 test/integrationTests/testAssets/slnWithCsproj/src/lib/Class1.cs create mode 100644 test/integrationTests/testAssets/slnWithCsproj/src/lib/lib.csproj create mode 100644 test/integrationTests/testAssets/slnWithCsproj/test/UnitTest1.cs create mode 100644 test/integrationTests/testAssets/slnWithCsproj/test/test.csproj diff --git a/.vscode/launch.json b/.vscode/launch.json index 804dddc499..3ea0238ba8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -29,6 +29,22 @@ "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ] + }, + { + "name": "Launch slnWithCsproj Workspace Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "${workspaceRoot}/test/integrationTests/testAssets/slnWithCsproj", + "--extensionDevelopmentPath=${workspaceRoot}", + "--extensionTestsPath=${workspaceRoot}/out/test/integrationTests" + ], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/out/test/**/*.js" + ] } ] } diff --git a/package.json b/package.json index 5e522b1af9..52bd2b1129 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "test": "npm-run-all test:unit test:integration", "test:unit": "cross-env CODE_TESTS_PATH=./out/test/unitTests npm run test:runInVsCode", "test:integration": "npm-run-all test:integration:*", + "test:integration:slnWithCsproj": "cross-env OSVC_SUITE=slnWithCsproj npm run test:runSuiteInVsCode", "test:runSuiteInVsCode": "cross-env CODE_TESTS_PATH=./out/test/integrationTests CODE_TESTS_WORKSPACE=./test/integrationTests/testAssets/$OSVC_SUITE npm run test:runInVsCode", "test:runInVsCode": "node ./test/runVsCodeTestsWithAbsolutePaths.js", "postinstall": "node ./node_modules/vscode/bin/install" diff --git a/test/integrationTests/testAssets/slnWithCsproj/slnWithCsproj.sln b/test/integrationTests/testAssets/slnWithCsproj/slnWithCsproj.sln new file mode 100644 index 0000000000..213e6c66b7 --- /dev/null +++ b/test/integrationTests/testAssets/slnWithCsproj/slnWithCsproj.sln @@ -0,0 +1,68 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D28FC441-C95D-47D2-8D5C-E401ABAD7C64}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app", "src\app\app.csproj", "{D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lib", "src\lib\lib.csproj", "{717BE881-D74C-45FC-B55D-2085499E1BF8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{4679428B-0CA0-4228-B8C0-B676B34A1B30}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Debug|x64.ActiveCfg = Debug|x64 + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Debug|x64.Build.0 = Debug|x64 + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Debug|x86.ActiveCfg = Debug|x86 + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Debug|x86.Build.0 = Debug|x86 + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Release|Any CPU.Build.0 = Release|Any CPU + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Release|x64.ActiveCfg = Release|x64 + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Release|x64.Build.0 = Release|x64 + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Release|x86.ActiveCfg = Release|x86 + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3}.Release|x86.Build.0 = Release|x86 + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Debug|x64.ActiveCfg = Debug|x64 + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Debug|x64.Build.0 = Debug|x64 + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Debug|x86.ActiveCfg = Debug|x86 + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Debug|x86.Build.0 = Debug|x86 + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Release|Any CPU.Build.0 = Release|Any CPU + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Release|x64.ActiveCfg = Release|x64 + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Release|x64.Build.0 = Release|x64 + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Release|x86.ActiveCfg = Release|x86 + {717BE881-D74C-45FC-B55D-2085499E1BF8}.Release|x86.Build.0 = Release|x86 + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Debug|x64.ActiveCfg = Debug|x64 + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Debug|x64.Build.0 = Debug|x64 + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Debug|x86.ActiveCfg = Debug|x86 + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Debug|x86.Build.0 = Debug|x86 + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Release|Any CPU.Build.0 = Release|Any CPU + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Release|x64.ActiveCfg = Release|x64 + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Release|x64.Build.0 = Release|x64 + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Release|x86.ActiveCfg = Release|x86 + {4679428B-0CA0-4228-B8C0-B676B34A1B30}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3} = {D28FC441-C95D-47D2-8D5C-E401ABAD7C64} + {717BE881-D74C-45FC-B55D-2085499E1BF8} = {D28FC441-C95D-47D2-8D5C-E401ABAD7C64} + EndGlobalSection +EndGlobal diff --git a/test/integrationTests/testAssets/slnWithCsproj/src/app/Program.cs b/test/integrationTests/testAssets/slnWithCsproj/src/app/Program.cs new file mode 100644 index 0000000000..a29e982532 --- /dev/null +++ b/test/integrationTests/testAssets/slnWithCsproj/src/app/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace app +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/test/integrationTests/testAssets/slnWithCsproj/src/app/app.csproj b/test/integrationTests/testAssets/slnWithCsproj/src/app/app.csproj new file mode 100644 index 0000000000..998c6a2eac --- /dev/null +++ b/test/integrationTests/testAssets/slnWithCsproj/src/app/app.csproj @@ -0,0 +1,12 @@ + + + + + + + + Exe + netcoreapp2.0 + + + diff --git a/test/integrationTests/testAssets/slnWithCsproj/src/lib/Class1.cs b/test/integrationTests/testAssets/slnWithCsproj/src/lib/Class1.cs new file mode 100644 index 0000000000..d07297bc60 --- /dev/null +++ b/test/integrationTests/testAssets/slnWithCsproj/src/lib/Class1.cs @@ -0,0 +1,8 @@ +using System; + +namespace lib +{ + public class Class1 + { + } +} diff --git a/test/integrationTests/testAssets/slnWithCsproj/src/lib/lib.csproj b/test/integrationTests/testAssets/slnWithCsproj/src/lib/lib.csproj new file mode 100644 index 0000000000..72764a6641 --- /dev/null +++ b/test/integrationTests/testAssets/slnWithCsproj/src/lib/lib.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.0 + + + diff --git a/test/integrationTests/testAssets/slnWithCsproj/test/UnitTest1.cs b/test/integrationTests/testAssets/slnWithCsproj/test/UnitTest1.cs new file mode 100644 index 0000000000..fa542cf33e --- /dev/null +++ b/test/integrationTests/testAssets/slnWithCsproj/test/UnitTest1.cs @@ -0,0 +1,14 @@ +using System; +using Xunit; + +namespace test +{ + public class UnitTest1 + { + [Fact] + public void Test1() + { + + } + } +} diff --git a/test/integrationTests/testAssets/slnWithCsproj/test/test.csproj b/test/integrationTests/testAssets/slnWithCsproj/test/test.csproj new file mode 100644 index 0000000000..edd8c463de --- /dev/null +++ b/test/integrationTests/testAssets/slnWithCsproj/test/test.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp2.0 + + false + + + + + + + + + From 10cbfefecf5ff6703953e75cab9d76af1e919611 Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Sat, 4 Nov 2017 16:29:31 -0700 Subject: [PATCH 05/10] Add test asset: single csproj --- .vscode/launch.json | 16 ++++++++++++++++ package.json | 1 + .../testAssets/singleCsproj.ts | 15 +++++++++++++++ .../testAssets/singleCsproj/Program.cs | 12 ++++++++++++ .../singleCsproj/singleCsproj.csproj | 8 ++++++++ .../testAssets/slnWithCsproj.ts | 19 +++++++++++++++++++ .../testAssets/testAssetWorkspace.ts | 5 +++++ 7 files changed, 76 insertions(+) create mode 100644 test/integrationTests/testAssets/singleCsproj.ts create mode 100644 test/integrationTests/testAssets/singleCsproj/Program.cs create mode 100644 test/integrationTests/testAssets/singleCsproj/singleCsproj.csproj create mode 100644 test/integrationTests/testAssets/slnWithCsproj.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 3ea0238ba8..c094fe619c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -30,6 +30,22 @@ "${workspaceRoot}/out/test/**/*.js" ] }, + { + "name": "Launch singleCsproj Workspace Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "${workspaceRoot}/test/integrationTests/testAssets/singleCsproj", + "--extensionDevelopmentPath=${workspaceRoot}", + "--extensionTestsPath=${workspaceRoot}/out/test/integrationTests" + ], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/out/test/**/*.js" + ] + }, { "name": "Launch slnWithCsproj Workspace Tests", "type": "extensionHost", diff --git a/package.json b/package.json index 52bd2b1129..7fd35fa6e4 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "test": "npm-run-all test:unit test:integration", "test:unit": "cross-env CODE_TESTS_PATH=./out/test/unitTests npm run test:runInVsCode", "test:integration": "npm-run-all test:integration:*", + "test:integration:singleCsproj": "cross-env OSVC_SUITE=singleCsproj npm run test:runSuiteInVsCode", "test:integration:slnWithCsproj": "cross-env OSVC_SUITE=slnWithCsproj npm run test:runSuiteInVsCode", "test:runSuiteInVsCode": "cross-env CODE_TESTS_PATH=./out/test/integrationTests CODE_TESTS_WORKSPACE=./test/integrationTests/testAssets/$OSVC_SUITE npm run test:runInVsCode", "test:runInVsCode": "node ./test/runVsCodeTestsWithAbsolutePaths.js", diff --git a/test/integrationTests/testAssets/singleCsproj.ts b/test/integrationTests/testAssets/singleCsproj.ts new file mode 100644 index 0000000000..6db898e311 --- /dev/null +++ b/test/integrationTests/testAssets/singleCsproj.ts @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ITestAssetWorkspace } from "./testAssets"; + +let workspace: ITestAssetWorkspace = { + description: "single csproj at root of workspace", + projects: [{ + relativePath: "singleCsproj.csproj" + }] +}; + +export default workspace; \ No newline at end of file diff --git a/test/integrationTests/testAssets/singleCsproj/Program.cs b/test/integrationTests/testAssets/singleCsproj/Program.cs new file mode 100644 index 0000000000..8f20c6374b --- /dev/null +++ b/test/integrationTests/testAssets/singleCsproj/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace singleCsproj +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/test/integrationTests/testAssets/singleCsproj/singleCsproj.csproj b/test/integrationTests/testAssets/singleCsproj/singleCsproj.csproj new file mode 100644 index 0000000000..8e047a019c --- /dev/null +++ b/test/integrationTests/testAssets/singleCsproj/singleCsproj.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp2.0 + + + diff --git a/test/integrationTests/testAssets/slnWithCsproj.ts b/test/integrationTests/testAssets/slnWithCsproj.ts new file mode 100644 index 0000000000..ea68da1f28 --- /dev/null +++ b/test/integrationTests/testAssets/slnWithCsproj.ts @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ITestAssetWorkspace } from "./testAssets"; + +let workspace: ITestAssetWorkspace = { + description: "sln with several csproj's", + projects: [{ + relativePath: "src/app/app.csproj" + },{ + relativePath: "src/lib/lib.csproj" + },{ + relativePath: "test/test.csproj" + }] +}; + +export default workspace; \ No newline at end of file diff --git a/test/integrationTests/testAssets/testAssetWorkspace.ts b/test/integrationTests/testAssets/testAssetWorkspace.ts index 8997c07e23..1a16fc81b9 100644 --- a/test/integrationTests/testAssets/testAssetWorkspace.ts +++ b/test/integrationTests/testAssets/testAssetWorkspace.ts @@ -8,7 +8,12 @@ import * as vscode from 'vscode'; import {ITestAssetWorkspace, TestAssetWorkspace} from './testAssets'; +import singleCsproj from './singleCsproj'; +import slnWithCsproj from './slnWithCsproj'; + const testAssetWorkspaces: { [x: string]: ITestAssetWorkspace } = { + singleCsproj, + slnWithCsproj }; const workspaceName = vscode.workspace.rootPath From 5d215f1a383125c83f6c0feefa54290ec2c64de0 Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Sun, 5 Nov 2017 12:54:32 -0800 Subject: [PATCH 06/10] Add Debug Launch integration test The integration test: - deletes the .vscode directory - deletes existing build artifacts - issues the `dotnet.generateAssets` command - executes the `.NET Core Launch (console)` debug configuration - validates that a debugSession becomes active - waits for debugging to stop To enable this, and other integration tests, I exposed an export on the csharp extension which can be awaited until the extension is initialized. Initialized is defined as omnisharp and the debugger being ready for invocation. Without awaiting this promise, commands issues to the extension have unpredictable behaviors since they are registered but not yet able to be handled. --- src/assets.ts | 43 ++++++++--------- src/coreclr-debug/activate.ts | 35 +++++++++----- src/main.ts | 44 +++++++++-------- src/omnisharp/extension.ts | 2 + .../launchConfiguration.integration.test.ts | 48 +++++++++++++++++++ test/integrationTests/poll.ts | 24 ++++++++++ .../integrationTests/testAssets/testAssets.ts | 12 +++++ 7 files changed, 153 insertions(+), 55 deletions(-) create mode 100644 test/integrationTests/launchConfiguration.integration.test.ts create mode 100644 test/integrationTests/poll.ts diff --git a/src/assets.ts b/src/assets.ts index 4a26cc8f0a..f25987559d 100644 --- a/src/assets.ts +++ b/src/assets.ts @@ -5,13 +5,14 @@ import * as fs from 'fs-extra'; import * as path from 'path'; -import * as vscode from 'vscode'; +import * as protocol from './omnisharp/protocol'; +import * as serverUtils from './omnisharp/utils'; import * as tasks from 'vscode-tasks'; +import * as util from './common'; +import * as vscode from 'vscode'; + import { OmniSharpServer } from './omnisharp/server'; -import * as serverUtils from './omnisharp/utils'; -import * as protocol from './omnisharp/protocol'; import { tolerantParse } from './json'; -import * as util from './common'; export class AssetGenerator { public rootPath: string; @@ -546,24 +547,20 @@ function shouldGenerateAssets(generator: AssetGenerator) { }); } -export function generateAssets(server: OmniSharpServer) { - serverUtils.requestWorkspaceInformation(server).then(info => { - if (protocol.containsDotNetCoreProjects(info)) { - const generator = new AssetGenerator(info); - getOperations(generator).then(operations => { - if (hasAddOperations(operations)) { - shouldGenerateAssets(generator).then(res => { - if (res) { - fs.ensureDir(generator.vscodeFolder, err => { - addAssets(generator, operations); - }); - } - }); - } - }); - } - else { - vscode.window.showErrorMessage("Could not locate .NET Core project. Assets were not generated."); +export async function generateAssets(server: OmniSharpServer) { + let workspaceInformation = await serverUtils.requestWorkspaceInformation(server); + if (protocol.containsDotNetCoreProjects(workspaceInformation)) { + const generator = new AssetGenerator(workspaceInformation); + let operations = await getOperations(generator); + if (hasAddOperations(operations)) { + let doGenerateAssets = await shouldGenerateAssets(generator); + if (doGenerateAssets) { + await fs.ensureDir(generator.vscodeFolder); + await addAssets(generator, operations); + } } - }); + } + else { + await vscode.window.showErrorMessage("Could not locate .NET Core project. Assets were not generated."); + } } diff --git a/src/coreclr-debug/activate.ts b/src/coreclr-debug/activate.ts index 9a3bfc603a..455dc7b30c 100644 --- a/src/coreclr-debug/activate.ts +++ b/src/coreclr-debug/activate.ts @@ -4,40 +4,49 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as vscode from 'vscode'; +import * as debugInstall from './install'; import * as os from 'os'; -import TelemetryReporter from 'vscode-extension-telemetry'; +import * as vscode from 'vscode'; + import { CoreClrDebugUtil, DotnetInfo, } from './util'; -import * as debugInstall from './install'; + import { Logger } from './../logger'; import { PlatformInformation } from './../platform'; +import TelemetryReporter from 'vscode-extension-telemetry'; let _debugUtil: CoreClrDebugUtil = null; let _reporter: TelemetryReporter = null; let _logger: Logger = null; -export function activate(thisExtension : vscode.Extension, context: vscode.ExtensionContext, reporter: TelemetryReporter, logger: Logger, channel: vscode.OutputChannel) { +export async function activate(thisExtension : vscode.Extension, context: vscode.ExtensionContext, reporter: TelemetryReporter, logger: Logger, channel: vscode.OutputChannel) { _debugUtil = new CoreClrDebugUtil(context.extensionPath, logger); _reporter = reporter; _logger = logger; if (!CoreClrDebugUtil.existsSync(_debugUtil.debugAdapterDir())) { - PlatformInformation.GetCurrent().then((info) => { - if (info.architecture !== "x86_64") { - if (info.isWindows() && info.architecture === "x86") { + let platformInformation: PlatformInformation; + + try { + platformInformation = await PlatformInformation.GetCurrent(); + } + catch (err) { + // Somehow we couldn't figure out the platform we are on + logger.appendLine("[ERROR]: C# Extension failed to install the debugger package"); + showInstallErrorMessage(channel); + } + + if (platformInformation) { + if (platformInformation.architecture !== "x86_64") { + if (platformInformation.isWindows() && platformInformation.architecture === "x86") { logger.appendLine(`[WARNING]: x86 Windows is not currently supported by the .NET Core debugger. Debugging will not be available.`); } else { - logger.appendLine(`[WARNING]: Processor architecture '${info.architecture}' is not currently supported by the .NET Core debugger. Debugging will not be available.`); + logger.appendLine(`[WARNING]: Processor architecture '${platformInformation.architecture}' is not currently supported by the .NET Core debugger. Debugging will not be available.`); } } else { logger.appendLine("[ERROR]: C# Extension failed to install the debugger package"); showInstallErrorMessage(channel); } - }, (err) => { - // Somehow we couldn't figure out the platform we are on - logger.appendLine("[ERROR]: C# Extension failed to install the debugger package"); - showInstallErrorMessage(channel); - }); + } } else if (!CoreClrDebugUtil.existsSync(_debugUtil.installCompleteFilePath())) { completeDebuggerInstall(logger, channel); } diff --git a/src/main.ts b/src/main.ts index bc862ac331..397fb4fcc8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,19 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; -import TelemetryReporter from 'vscode-extension-telemetry'; - -import * as coreclrdebug from './coreclr-debug/activate'; import * as OmniSharp from './omnisharp/extension'; +import * as coreclrdebug from './coreclr-debug/activate'; import * as util from './common'; -import { Logger } from './logger'; +import * as vscode from 'vscode'; + import { CSharpExtDownloader } from './CSharpExtDownloader'; +import { Logger } from './logger'; +import TelemetryReporter from 'vscode-extension-telemetry'; import { addJSONProviders } from './features/json/jsonContributions'; let _channel: vscode.OutputChannel = null; -export function activate(context: vscode.ExtensionContext): any { +export async function activate(context: vscode.ExtensionContext): Promise<{ initializationFinished: Promise }> { const extensionId = 'ms-vscode.csharp'; const extension = vscode.extensions.getExtension(extensionId); @@ -29,19 +29,25 @@ export function activate(context: vscode.ExtensionContext): any { let logger = new Logger(text => _channel.append(text)); - ensureRuntimeDependencies(extension, logger, reporter) - .then((success : boolean) => { - // activate language services - OmniSharp.activate(context, reporter, _channel); - - // register JSON completion & hover providers for project.json - context.subscriptions.push(addJSONProviders()); - - if (success) { - // activate coreclr-debug - coreclrdebug.activate(extension, context, reporter, logger, _channel); - } - }); + let runtimeDependenciesExist = await ensureRuntimeDependencies(extension, logger, reporter); + + if (!runtimeDependenciesExist) { + //do something + } + + // activate language services + let omniSharpPromise = OmniSharp.activate(context, reporter, _channel); + + // register JSON completion & hover providers for project.json + context.subscriptions.push(addJSONProviders()); + + // activate coreclr-debug + let coreClrDebugPromise = coreclrdebug.activate(extension, context, reporter, logger, _channel); + + return { + initializationFinished: Promise.all([omniSharpPromise, coreClrDebugPromise]) + .then(a => {}) + }; } function ensureRuntimeDependencies(extension: vscode.Extension, logger: Logger, reporter: TelemetryReporter): Promise { diff --git a/src/omnisharp/extension.ts b/src/omnisharp/extension.ts index 99d148f600..41a3a75ff4 100644 --- a/src/omnisharp/extension.ts +++ b/src/omnisharp/extension.ts @@ -157,4 +157,6 @@ export function activate(context: vscode.ExtensionContext, reporter: TelemetryRe disposables.push(vscode.debug.registerDebugConfigurationProvider('coreclr', new CSharpConfigurationProvider(server))); context.subscriptions.push(...disposables); + + return new Promise(resolve => server.onServerStart(e => resolve(e))); } \ No newline at end of file diff --git a/test/integrationTests/launchConfiguration.integration.test.ts b/test/integrationTests/launchConfiguration.integration.test.ts new file mode 100644 index 0000000000..a38fd9b355 --- /dev/null +++ b/test/integrationTests/launchConfiguration.integration.test.ts @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as fs from 'async-file'; +import * as vscode from 'vscode'; + +import poll from './poll'; +import { should } from 'chai'; +import testAssetWorkspace from './testAssets/testAssetWorkspace'; + +const chai = require('chai'); +chai.use(require('chai-arrays')); +chai.use(require('chai-fs')); + +suite(`Tasks generation: ${testAssetWorkspace.description}`, function() { + suiteSetup(async function() { + should(); + + let csharpExtension = vscode.extensions.getExtension("ms-vscode.csharp"); + if (!csharpExtension.isActive) { + await csharpExtension.activate(); + } + + testAssetWorkspace.deleteBuildArtifacts(); + + await fs.rimraf(testAssetWorkspace.vsCodeDirectoryPath); + + await csharpExtension.exports.initializationFinished; + + await vscode.commands.executeCommand("dotnet.generateAssets"); + + await poll(async () => await fs.exists(testAssetWorkspace.launchJsonPath), 10000, 100); + }); + + test("Starting .NET Core Launch (console) from the workspace root should create an Active Debug Session", async () => { + await vscode.debug.startDebugging(vscode.workspace.workspaceFolders[0], ".NET Core Launch (console)"); + + let debugSessionTerminated = new Promise(resolve => { + vscode.debug.onDidTerminateDebugSession((e) => resolve()); + }); + + vscode.debug.activeDebugSession.type.should.equal("coreclr"); + + await debugSessionTerminated; + }); +}); \ No newline at end of file diff --git a/test/integrationTests/poll.ts b/test/integrationTests/poll.ts new file mode 100644 index 0000000000..2ada6c7d7e --- /dev/null +++ b/test/integrationTests/poll.ts @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export default async function poll(getValue: () => T, duration: number, step: number): Promise { + while (duration > 0) { + let value = await getValue(); + + if (value) { + return value; + } + + await sleep(step); + + duration -= step; + } + + throw new Error("Polling did not succeed within the alotted duration."); +} + +function sleep(ms = 0) { + return new Promise(r => setTimeout(r, ms)); +} \ No newline at end of file diff --git a/test/integrationTests/testAssets/testAssets.ts b/test/integrationTests/testAssets/testAssets.ts index 63da6a9f86..407bd72976 100644 --- a/test/integrationTests/testAssets/testAssets.ts +++ b/test/integrationTests/testAssets/testAssets.ts @@ -45,6 +45,18 @@ export class TestAssetWorkspace { async deleteBuildArtifacts(): Promise { this.projects.forEach(async p => await p.deleteBuildArtifacts()); } + + get vsCodeDirectoryPath(): string { + return path.join(vscode.workspace.rootPath, ".vscode");; + } + + get launchJsonPath(): string { + return path.join(this.vsCodeDirectoryPath, "launch.json"); + } + + get tasksJsonPath(): string { + return path.join(this.vsCodeDirectoryPath, "tasks.json"); + } description: string; From ddc6145bca4a00173eabdf48c7c0e40ab741830b Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Mon, 6 Nov 2017 14:52:32 -0800 Subject: [PATCH 07/10] Increase timeout I believe this is downloading the extension's dependencies. --- test/integrationTests/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integrationTests/index.ts b/test/integrationTests/index.ts index cda6a4004a..9de6cb03a1 100644 --- a/test/integrationTests/index.ts +++ b/test/integrationTests/index.ts @@ -21,7 +21,7 @@ var testRunner = require('vscode/lib/testrunner'); // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info testRunner.configure({ - timeout: 10000, + timeout: 60000, ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) useColors: true // colored output from test results }); From 63c74d2edfcf796de3026962515117eb644d6ee1 Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Mon, 6 Nov 2017 19:48:00 -0800 Subject: [PATCH 08/10] PR feedback --- src/main.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main.ts b/src/main.ts index 397fb4fcc8..fc0b95c35b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -30,10 +30,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<{ init let logger = new Logger(text => _channel.append(text)); let runtimeDependenciesExist = await ensureRuntimeDependencies(extension, logger, reporter); - - if (!runtimeDependenciesExist) { - //do something - } // activate language services let omniSharpPromise = OmniSharp.activate(context, reporter, _channel); @@ -41,9 +37,12 @@ export async function activate(context: vscode.ExtensionContext): Promise<{ init // register JSON completion & hover providers for project.json context.subscriptions.push(addJSONProviders()); - // activate coreclr-debug - let coreClrDebugPromise = coreclrdebug.activate(extension, context, reporter, logger, _channel); - + let coreClrDebugPromise = Promise.resolve(); + if (runtimeDependenciesExist) { + // activate coreclr-debug + coreClrDebugPromise = coreclrdebug.activate(extension, context, reporter, logger, _channel); + } + return { initializationFinished: Promise.all([omniSharpPromise, coreClrDebugPromise]) .then(a => {}) From fa293d2efea518897d0b8e3d638bfe036eacfd75 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 7 Nov 2017 09:44:28 -0800 Subject: [PATCH 09/10] Disable .NET restore warnings now that we have C# project test assets --- .vscode/settings.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index e438260534..5095069000 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,8 @@ "**/node_modules": true, "out/": true }, + + "csharp.suppressDotnetRestoreNotification": true, "tslint.rulesDirectory": "node_modules/tslint-microsoft-contrib", "typescript.tsdk": "./node_modules/typescript/lib" From 64204656725ecc15b0b0c130f15d27c640de158c Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 7 Nov 2017 10:13:23 -0800 Subject: [PATCH 10/10] Update asset generation to be workspace folder aware Asset generation now uses the workspace information from OmniSharp to determine which workspace folder to use in the face of a multi-root workspace. --- src/assets.ts | 50 ++++++++++++++++++++++++----------- test/unitTests/assets.test.ts | 33 ++++++++++++++--------- 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/assets.ts b/src/assets.ts index f25987559d..0efce2f484 100644 --- a/src/assets.ts +++ b/src/assets.ts @@ -15,7 +15,7 @@ import { OmniSharpServer } from './omnisharp/server'; import { tolerantParse } from './json'; export class AssetGenerator { - public rootPath: string; + public workspaceFolder: vscode.WorkspaceFolder; public vscodeFolder: string; public tasksJsonPath: string; public launchJsonPath: string; @@ -27,13 +27,33 @@ export class AssetGenerator { private executableName: string; private configurationName: string; - public constructor(workspaceInfo: protocol.WorkspaceInformationResponse, rootPath: string = vscode.workspace.rootPath) { - if (rootPath === null || rootPath === undefined) { - throw new Error('rootPath must set.'); + public constructor(workspaceInfo: protocol.WorkspaceInformationResponse, workspaceFolder: vscode.WorkspaceFolder = undefined) { + if (workspaceFolder) { + this.workspaceFolder = workspaceFolder; + } + else { + let resourcePath: string = undefined; + + if (!resourcePath && workspaceInfo.Cake) { + resourcePath = workspaceInfo.Cake.Path; + } + + if (!resourcePath && workspaceInfo.ScriptCs) { + resourcePath = workspaceInfo.ScriptCs.Path; + } + + if (!resourcePath && workspaceInfo.DotNet && workspaceInfo.DotNet.Projects.length > 0) { + resourcePath = workspaceInfo.DotNet.Projects[0].Path; + } + + if (!resourcePath && workspaceInfo.MsBuild) { + resourcePath = workspaceInfo.MsBuild.SolutionPath; + } + + this.workspaceFolder = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(resourcePath)); } - this.rootPath = rootPath; - this.vscodeFolder = path.join(this.rootPath, '.vscode'); + this.vscodeFolder = path.join(this.workspaceFolder.uri.fsPath, '.vscode'); this.tasksJsonPath = path.join(this.vscodeFolder, 'tasks.json'); this.launchJsonPath = path.join(this.vscodeFolder, 'launch.json'); @@ -133,7 +153,7 @@ export class AssetGenerator { let result = '${workspaceFolder}'; if (this.projectPath) { - result = path.join(result, path.relative(this.rootPath, this.projectPath)); + result = path.join(result, path.relative(this.workspaceFolder.uri.fsPath, this.projectPath)); } result = path.join(result, `bin/${this.configurationName}/${this.targetFramework}/${this.executableName}`); @@ -141,7 +161,7 @@ export class AssetGenerator { return result; } - private computeWorkingDirectory() : string { + private computeWorkingDirectory(): string { if (!this.hasProject) { // If there's no target project data, use a placeholder for the path. return '${workspaceFolder}'; @@ -150,7 +170,7 @@ export class AssetGenerator { let result = '${workspaceFolder}'; if (this.projectPath) { - result = path.join(result, path.relative(this.rootPath, this.projectPath)); + result = path.join(result, path.relative(this.workspaceFolder.uri.fsPath, this.projectPath)); } return result; @@ -180,7 +200,7 @@ export class AssetGenerator { private createBuildTaskDescription(): tasks.TaskDescription { let buildPath = ''; if (this.hasProject) { - buildPath = path.join('${workspaceFolder}', path.relative(this.rootPath, this.projectFilePath)); + buildPath = path.join('${workspaceFolder}', path.relative(this.workspaceFolder.uri.fsPath, this.projectFilePath)); } return { @@ -236,7 +256,7 @@ export function createWebLaunchConfiguration(programPath: string, workingDirecto }`; } - export function createLaunchConfiguration(programPath: string, workingDirectory: string): string { +export function createLaunchConfiguration(programPath: string, workingDirectory: string): string { return ` { "name": ".NET Core Launch (console)", @@ -379,13 +399,13 @@ interface PromptItem extends vscode.MessageItem { result: PromptResult; } -function promptToAddAssets() { +function promptToAddAssets(workspaceFolder: vscode.WorkspaceFolder) { return new Promise((resolve, reject) => { const yesItem: PromptItem = { title: 'Yes', result: PromptResult.Yes }; const noItem: PromptItem = { title: 'Not Now', result: PromptResult.No, isCloseAffordance: true }; const disableItem: PromptItem = { title: "Don't Ask Again", result: PromptResult.Disable }; - const projectName = path.basename(vscode.workspace.rootPath); + const projectName = path.basename(workspaceFolder.uri.fsPath); vscode.window.showWarningMessage( `Required assets to build and debug are missing from '${projectName}'. Add them?`, disableItem, noItem, yesItem) @@ -464,7 +484,7 @@ export enum AddAssetResult { export function addAssetsIfNecessary(server: OmniSharpServer): Promise { return new Promise((resolve, reject) => { - if (!vscode.workspace.rootPath) { + if (!vscode.workspace.workspaceFolders) { return resolve(AddAssetResult.NotApplicable); } @@ -477,7 +497,7 @@ export function addAssetsIfNecessary(server: OmniSharpServer): Promise { + promptToAddAssets(generator.workspaceFolder).then(result => { if (result === PromptResult.Disable) { return resolve(AddAssetResult.Disable); } diff --git a/test/unitTests/assets.test.ts b/test/unitTests/assets.test.ts index 606f9b5d15..cb8bddec0a 100644 --- a/test/unitTests/assets.test.ts +++ b/test/unitTests/assets.test.ts @@ -5,18 +5,27 @@ import * as path from 'path'; import * as protocol from '../../src/omnisharp/protocol'; +import * as vscode from 'vscode'; import { AssetGenerator } from '../../src/assets'; import { parse } from 'jsonc-parser'; import { should } from 'chai'; +function createMockWorkspaceFolder(rootPath: string) : vscode.WorkspaceFolder { + return { + uri: vscode.Uri.file(rootPath), + name: undefined, + index: undefined + } +} + suite("Asset generation: project.json", () => { suiteSetup(() => should()); test("Create tasks.json for project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createDotNetWorkspaceInformation(rootPath, 'testApp.dll', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let tasksJson = generator.createTasksConfiguration(); let buildPath = tasksJson.tasks[0].args[1]; @@ -28,7 +37,7 @@ suite("Asset generation: project.json", () => { test("Create tasks.json for nested project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createDotNetWorkspaceInformation(path.join(rootPath, 'nested'), 'testApp.dll', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let tasksJson = generator.createTasksConfiguration(); let buildPath = tasksJson.tasks[0].args[1]; @@ -40,7 +49,7 @@ suite("Asset generation: project.json", () => { test("Create launch.json for project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createDotNetWorkspaceInformation(rootPath, 'testApp.dll', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ false), undefined, { disallowComments: true }); let programPath = launchJson[0].program; @@ -52,7 +61,7 @@ suite("Asset generation: project.json", () => { test("Create launch.json for nested project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createDotNetWorkspaceInformation(path.join(rootPath, 'nested'), 'testApp.dll', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ false), undefined, { disallowComments: true }); let programPath = launchJson[0].program; @@ -64,7 +73,7 @@ suite("Asset generation: project.json", () => { test("Create launch.json for web project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createDotNetWorkspaceInformation(rootPath, 'testApp.dll', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ true), undefined, { disallowComments: true }); let programPath = launchJson[0].program; @@ -76,7 +85,7 @@ suite("Asset generation: project.json", () => { test("Create launch.json for nested web project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createDotNetWorkspaceInformation(path.join(rootPath, 'nested'), 'testApp.dll', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ true), undefined, { disallowComments: true }); let programPath = launchJson[0].program; @@ -124,7 +133,7 @@ suite("Asset generation: csproj", () => { test("Create tasks.json for project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'testApp.csproj'), 'testApp', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let tasksJson = generator.createTasksConfiguration(); let buildPath = tasksJson.tasks[0].args[1]; @@ -136,7 +145,7 @@ suite("Asset generation: csproj", () => { test("Create tasks.json for nested project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'nested', 'testApp.csproj'), 'testApp', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let tasksJson = generator.createTasksConfiguration(); let buildPath = tasksJson.tasks[0].args[1]; @@ -148,7 +157,7 @@ suite("Asset generation: csproj", () => { test("Create launch.json for project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'testApp.csproj'), 'testApp', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ false), undefined, { disallowComments: true }); let programPath = launchJson[0].program; @@ -160,7 +169,7 @@ suite("Asset generation: csproj", () => { test("Create launch.json for nested project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'nested', 'testApp.csproj'), 'testApp', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ false), undefined, { disallowComments: true }); let programPath = launchJson[0].program; @@ -172,7 +181,7 @@ suite("Asset generation: csproj", () => { test("Create launch.json for web project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'testApp.csproj'), 'testApp', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ true), undefined, { disallowComments: true }); let programPath = launchJson[0].program; @@ -184,7 +193,7 @@ suite("Asset generation: csproj", () => { test("Create launch.json for nested web project opened in workspace", () => { let rootPath = path.resolve('testRoot'); let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'nested', 'testApp.csproj'), 'testApp', 'netcoreapp1.0'); - let generator = new AssetGenerator(info, rootPath); + let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath)); let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ true), undefined, { disallowComments: true }); let programPath = launchJson[0].program;