diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f396e4797..957bb6949 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,10 +17,10 @@ jobs: - name: Setup virtual display run: /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & - - name: Install .NET Core 3.1 SDK + - name: Install .NET Core 5.0 SDK uses: actions/setup-dotnet@v1.7.2 with: - dotnet-version: 3.1.x + dotnet-version: 5.0.x - name: Install Node.js 15.x uses: actions/setup-node@v1 diff --git a/.vscode/launch.json b/.vscode/launch.json index 1971bf918..84d48e5d3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -153,6 +153,31 @@ ], "preLaunchTask": "buildDev" }, + { + "name": "Launch slnWithGenerator Workspace Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--disable-extensions", + "${workspaceRoot}/test/integrationTests/testAssets/slnWithGenerator", + "--extensionDevelopmentPath=${workspaceRoot}", + "--extensionTestsPath=${workspaceRoot}/out/test/integrationTests" + ], + "env": { + "CODE_WORKSPACE_ROOT": "${workspaceRoot}", + "CODE_TESTS_PATH": "${workspaceRoot}/out/test/integrationTests", + "CODE_TESTS_WORKSPACE": "${workspaceRoot}/test/integrationTests/testAssets/slnWithGenerator", + "CODE_EXTENSIONS_PATH": "${workspaceRoot}", + "OSVC_SUITE": "slnWithGenerator" + }, + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/dist/*.js" + ], + "preLaunchTask": "buildDev" + }, { "type": "node", "request": "launch", @@ -169,4 +194,4 @@ "cwd": "${workspaceFolder}" } ] -} \ No newline at end of file +} diff --git a/CHANGELOG.md b/CHANGELOG.md index d2429bf27..9c5370d84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * As a workaround, make an edit within the file before using Rename Symbol. ## 1.23.13 (Not yet released) +* Support V2 version of GoToDefinition, which can show more than one location for partial types and show source-generated file information (PR: [#4581](https://github.com/OmniSharp/omnisharp-vscode/pull/4581)) * Add command 'listRemoteDockerProcess' and variable 'pickRemoteDockerProcess' ([#4607](https://github.com/OmniSharp/omnisharp-vscode/issues/4607), PR: [#4617](https://www.github.com/OmniSharp/omnisharp-vscode/pull/4617)) * Ensure we only start one instance of OmniSharp server (PR: [#4612](https://www.github.com/OmniSharp/omnisharp-vscode/pull/4612)) * Update OmniSharp version to 1.37.11 diff --git a/README.md b/README.md index 8f95fad52..7dce9a1b1 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ For Windows users who have Visual Studio installed, this means you will need to For MacOS and Linux users who have Mono installed, this means you will need to set `omnisharp.useGlobalMono` to `never` until a version of Mono ships with MSBuild 16.8. ## What's new in 1.23.13 +- Support V2 version of GoToDefinition, which can show more than one location for partial types and show source-generated file information (PR: [#4581](https://github.com/OmniSharp/omnisharp-vscode/pull/4581)) - Add command 'listRemoteDockerProcess' and variable 'pickRemoteDockerProcess' ([#4607](https://github.com/OmniSharp/omnisharp-vscode/issues/4607), PR: [#4617](https://www.github.com/OmniSharp/omnisharp-vscode/pull/4617)) - Ensure we only start one instance of OmniSharp server (PR: [#4612](https://www.github.com/OmniSharp/omnisharp-vscode/pull/4612)) - Update OmniSharp version to 1.37.11 diff --git a/src/common.ts b/src/common.ts index fdf2b419a..f46eca015 100644 --- a/src/common.ts +++ b/src/common.ts @@ -71,7 +71,9 @@ export async function execChildProcess(command: string, workingDirectory: string return new Promise((resolve, reject) => { cp.exec(command, { cwd: workingDirectory, maxBuffer: 500 * 1024 }, (error, stdout, stderr) => { if (error) { - reject(error); + reject(`${error} +${stdout} +${stderr}`); } else if (stderr && !stderr.includes("screen size is bogus")) { reject(new Error(stderr)); diff --git a/src/features/definitionProvider.ts b/src/features/definitionProvider.ts index d0b94707d..499e2a097 100644 --- a/src/features/definitionProvider.ts +++ b/src/features/definitionProvider.ts @@ -5,66 +5,84 @@ import * as serverUtils from '../omnisharp/utils'; import { CancellationToken, DefinitionProvider, Location, Position, TextDocument, Uri } from 'vscode'; -import { GoToDefinitionRequest, MetadataRequest, MetadataSource } from '../omnisharp/protocol'; -import { createRequest, toLocation, toLocationFromUri } from '../omnisharp/typeConversion'; +import { MetadataRequest, MetadataSource, V2 } from '../omnisharp/protocol'; +import { createRequest, toRange3, toVscodeLocation } from '../omnisharp/typeConversion'; import AbstractSupport from './abstractProvider'; -import DefinitionMetadataDocumentProvider from './definitionMetadataDocumentProvider'; +import DefinitionMetadataOrSourceGeneratedDocumentProvider from './definitionMetadataDocumentProvider'; import { OmniSharpServer } from '../omnisharp/server'; import { LanguageMiddlewareFeature } from '../omnisharp/LanguageMiddlewareFeature'; +import SourceGeneratedDocumentProvider from './sourceGeneratedDocumentProvider'; export default class CSharpDefinitionProvider extends AbstractSupport implements DefinitionProvider { - private _definitionMetadataDocumentProvider: DefinitionMetadataDocumentProvider; - - constructor(server: OmniSharpServer, definitionMetadataDocumentProvider: DefinitionMetadataDocumentProvider, languageMiddlewareFeature: LanguageMiddlewareFeature) { + constructor( + server: OmniSharpServer, + private definitionMetadataDocumentProvider: DefinitionMetadataOrSourceGeneratedDocumentProvider, + private sourceGeneratedDocumentProvider: SourceGeneratedDocumentProvider, + languageMiddlewareFeature: LanguageMiddlewareFeature) { super(server, languageMiddlewareFeature); - - this._definitionMetadataDocumentProvider = definitionMetadataDocumentProvider; } public async provideDefinition(document: TextDocument, position: Position, token: CancellationToken): Promise { - let req = createRequest(document, position); + let req = createRequest(document, position); req.WantMetadata = true; - let location: Location; + const locations: Location[] = []; try { - let gotoDefinitionResponse = await serverUtils.goToDefinition(this._server, req, token); + const gotoDefinitionResponse = await serverUtils.goToDefinition(this._server, req, token); // the defintion is in source - if (gotoDefinitionResponse && gotoDefinitionResponse.FileName) { + if (gotoDefinitionResponse && gotoDefinitionResponse.Definitions) { - // if it is part of an already used metadata file, retrieve its uri instead of going to the physical file - if (gotoDefinitionResponse.FileName.startsWith("$metadata$")) { - const uri = this._definitionMetadataDocumentProvider.getExistingMetadataResponseUri(gotoDefinitionResponse.FileName); - location = toLocationFromUri(uri, gotoDefinitionResponse); - } else { - // if it is a normal source definition, convert the response to a location - location = toLocation(gotoDefinitionResponse); - } + for (const definition of gotoDefinitionResponse.Definitions) { + if (definition.Location.FileName.startsWith("$metadata$")) { + // if it is part of an already used metadata file, retrieve its uri instead of going to the physical file + const uri = this.definitionMetadataDocumentProvider.getExistingMetadataResponseUri(definition.Location.FileName); + const vscodeRange = toRange3(definition.Location.Range); + locations.push(new Location(uri, vscodeRange)); + } else if (definition.MetadataSource) { + // the definition is in metadata + const metadataSource: MetadataSource = definition.MetadataSource; - // the definition is in metadata - } else if (gotoDefinitionResponse.MetadataSource) { - const metadataSource: MetadataSource = gotoDefinitionResponse.MetadataSource; + // go to metadata endpoint for more information + const metadataResponse = await serverUtils.getMetadata(this._server, { + Timeout: 5000, + AssemblyName: metadataSource.AssemblyName, + VersionNumber: metadataSource.VersionNumber, + ProjectName: metadataSource.ProjectName, + Language: metadataSource.Language, + TypeName: metadataSource.TypeName + }); - // go to metadata endpoint for more information - const metadataResponse = await serverUtils.getMetadata(this._server, { - Timeout: 5000, - AssemblyName: metadataSource.AssemblyName, - VersionNumber: metadataSource.VersionNumber, - ProjectName: metadataSource.ProjectName, - Language: metadataSource.Language, - TypeName: metadataSource.TypeName - }); + if (!metadataResponse || !metadataResponse.Source || !metadataResponse.SourceName) { + continue; + } - if (!metadataResponse || !metadataResponse.Source || !metadataResponse.SourceName) { - return; - } + const uri: Uri = this.definitionMetadataDocumentProvider.addMetadataResponse(metadataResponse); + const vscodeRange = toRange3(definition.Location.Range); + locations.push(new Location(uri, vscodeRange)); + } else if (definition.SourceGeneratedFileInfo) { + // File is source generated + let uri = this.sourceGeneratedDocumentProvider.tryGetExistingSourceGeneratedFile(definition.SourceGeneratedFileInfo); + if (!uri) { + const sourceGeneratedFileResponse = await serverUtils.getSourceGeneratedFile(this._server, definition.SourceGeneratedFileInfo, token); - const uri: Uri = this._definitionMetadataDocumentProvider.addMetadataResponse(metadataResponse); - location = new Location(uri, new Position(gotoDefinitionResponse.Line, gotoDefinitionResponse.Column)); + if (!sourceGeneratedFileResponse || !sourceGeneratedFileResponse.Source || !sourceGeneratedFileResponse.SourceName) { + continue; + } + + uri = this.sourceGeneratedDocumentProvider.addSourceGeneratedFile(definition.SourceGeneratedFileInfo, sourceGeneratedFileResponse); + } + + locations.push(new Location(uri, toRange3(definition.Location.Range))); + } else { + // if it is a normal source definition, convert the response to a location + locations.push(toVscodeLocation(definition.Location)); + } + } } // Allow language middlewares to re-map its edits if necessary. - const result = await this._languageMiddlewareFeature.remap("remapLocations", [location], token); + const result = await this._languageMiddlewareFeature.remap("remapLocations", locations, token); return result; } catch (error) { diff --git a/src/features/sourceGeneratedDocumentProvider.ts b/src/features/sourceGeneratedDocumentProvider.ts new file mode 100644 index 000000000..13a9e3db6 --- /dev/null +++ b/src/features/sourceGeneratedDocumentProvider.ts @@ -0,0 +1,127 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as serverUtils from '../omnisharp/utils'; +import { Event, EventEmitter, TextDocument, TextDocumentContentProvider, TextEditor, Uri, window, workspace } from 'vscode'; +import { IDisposable } from '../Disposable'; +import { SourceGeneratedFileInfo, SourceGeneratedFileResponse, UpdateType } from '../omnisharp/protocol'; +import { OmniSharpServer } from '../omnisharp/server'; + +export default class SourceGeneratedDocumentProvider implements TextDocumentContentProvider, IDisposable { + readonly scheme = "omnisharp-source-generated"; + private _registration: IDisposable; + private _documents: Map; + private _uriToDocumentInfo: Map; + private _documentClosedSubscription: IDisposable; + private _visibleTextEditorsChangedSubscription: IDisposable; + private _onDidChangeEmitter: EventEmitter; + public onDidChange: Event; + + constructor(private server: OmniSharpServer) { + this._documents = new Map(); + this._uriToDocumentInfo = new Map(); + this._documentClosedSubscription = workspace.onDidCloseTextDocument(this.onTextDocumentClosed, this); + this._visibleTextEditorsChangedSubscription = window.onDidChangeVisibleTextEditors(this.onVisibleTextEditorsChanged, this); + this._onDidChangeEmitter = new EventEmitter(); + this.onDidChange = this._onDidChangeEmitter.event; + } + + private async onTextDocumentClosed(document: TextDocument) { + const uriString = document.uri.toString(); + if (this._uriToDocumentInfo.has(uriString)) { + const info = this._uriToDocumentInfo.get(uriString); + this._documents.delete(info); + this._uriToDocumentInfo.delete(uriString); + await serverUtils.sourceGeneratedFileClosed(this.server, info); + } + } + + private async onVisibleTextEditorsChanged(editors?: TextEditor[]) { + for (const editor of editors) { + const documentUri = editor.document.uri; + const uriString = documentUri.toString(); + if (this._uriToDocumentInfo.has(uriString)) { + try { + const existingInfo = this._uriToDocumentInfo.get(uriString); + const existingResponse = this._documents.get(existingInfo); + const update = await serverUtils.getUpdatedSourceGeneratedFile(this.server, existingInfo); + if (!update) { + continue; + } + + switch (update.UpdateType) { + case UpdateType.Deleted: + this._documents.set(existingInfo, { Source: "Document is no longer being generated.", SourceName: existingResponse.SourceName }); + break; + case UpdateType.Modified: + this._documents.set(existingInfo, { Source: update.Source, SourceName: existingResponse.SourceName }); + break; + case UpdateType.Unchanged: + continue; + } + + this._onDidChangeEmitter.fire(documentUri); + } catch { + continue; + } + } + } + } + + public register(): void { + this._registration = workspace.registerTextDocumentContentProvider(this.scheme, this); + } + + public dispose() { + this._registration.dispose(); + this._documentClosedSubscription.dispose(); + this._visibleTextEditorsChangedSubscription.dispose(); + this._documents.clear(); + } + + public tryGetExistingSourceGeneratedFile(fileInfo: SourceGeneratedFileInfo): Uri | undefined { + if (this._documents.has(fileInfo)) { + return this.getUriForName(this._documents.get(fileInfo).SourceName); + } + + return undefined; + } + + public addSourceGeneratedFile(fileInfo: SourceGeneratedFileInfo, response: SourceGeneratedFileResponse): Uri { + if (this._documents.has(fileInfo)) { + // Raced with something, return the existing one + return this.tryGetExistingSourceGeneratedFile(fileInfo); + } + + const uri = this.getUriForName(response.SourceName); + const uriString = uri.toString(); + + let triggerUpdate = false; + + if (this._uriToDocumentInfo.has(uriString)) { + // Old version of the file in the cache. Remove it, and after it's replaced trigger vscode to update the file. + this._documents.delete(fileInfo); + this._uriToDocumentInfo.delete(uriString); + triggerUpdate = true; + } + + this._documents.set(fileInfo, response); + this._uriToDocumentInfo.set(uriString, fileInfo); + + if (triggerUpdate) { + this._onDidChangeEmitter.fire(uri); + } + + return uri; + } + + public provideTextDocumentContent(uri: Uri): string { + return this._documents.get(this._uriToDocumentInfo.get(uri.toString())).Source; + } + + private getUriForName(sourceName: string): Uri { + return Uri.parse(this.scheme + ":///" + sourceName); + } +} diff --git a/src/omnisharp/extension.ts b/src/omnisharp/extension.ts index a3e9bcc56..86a7d34ee 100644 --- a/src/omnisharp/extension.ts +++ b/src/omnisharp/extension.ts @@ -41,6 +41,7 @@ import { getMonoVersion } from '../utils/getMonoVersion'; import { FixAllProvider } from '../features/fixAllProvider'; import { LanguageMiddlewareFeature } from './LanguageMiddlewareFeature'; import SemanticTokensProvider from '../features/semanticTokensProvider'; +import SourceGeneratedDocumentProvider from '../features/sourceGeneratedDocumentProvider'; export interface ActivationResult { readonly server: OmniSharpServer; @@ -72,7 +73,10 @@ export async function activate(context: vscode.ExtensionContext, packageJSON: an const definitionMetadataDocumentProvider = new DefinitionMetadataDocumentProvider(); definitionMetadataDocumentProvider.register(); localDisposables.add(definitionMetadataDocumentProvider); - const definitionProvider = new DefinitionProvider(server, definitionMetadataDocumentProvider, languageMiddlewareFeature); + const sourceGeneratedDocumentProvider = new SourceGeneratedDocumentProvider(server); + sourceGeneratedDocumentProvider.register(); + localDisposables.add(sourceGeneratedDocumentProvider); + const definitionProvider = new DefinitionProvider(server, definitionMetadataDocumentProvider, sourceGeneratedDocumentProvider, languageMiddlewareFeature); localDisposables.add(vscode.languages.registerDefinitionProvider(documentSelector, definitionProvider)); localDisposables.add(vscode.languages.registerDefinitionProvider({ scheme: definitionMetadataDocumentProvider.scheme }, definitionProvider)); localDisposables.add(vscode.languages.registerImplementationProvider(documentSelector, new ImplementationProvider(server, languageMiddlewareFeature))); diff --git a/src/omnisharp/prioritization.ts b/src/omnisharp/prioritization.ts index ac5c5b7ed..1484947bf 100644 --- a/src/omnisharp/prioritization.ts +++ b/src/omnisharp/prioritization.ts @@ -19,7 +19,7 @@ const normalCommands = [ protocol.Requests.FindSymbols, protocol.Requests.FindUsages, protocol.Requests.GetCodeActions, - protocol.Requests.GoToDefinition, + protocol.V2.Requests.GoToDefinition, protocol.Requests.RunCodeAction, protocol.Requests.SignatureHelp, protocol.Requests.TypeLookup @@ -58,4 +58,4 @@ export function isDeferredCommand(command: string) { deferredSet.add(command); return true; -} \ No newline at end of file +} diff --git a/src/omnisharp/protocol.ts b/src/omnisharp/protocol.ts index 9aea9ea35..021d17ab9 100644 --- a/src/omnisharp/protocol.ts +++ b/src/omnisharp/protocol.ts @@ -17,7 +17,6 @@ export module Requests { export const FormatAfterKeystroke = '/formatAfterKeystroke'; export const FormatRange = '/formatRange'; export const GetCodeActions = '/getcodeactions'; - export const GoToDefinition = '/gotoDefinition'; export const FindImplementations = '/findimplementations'; export const Project = '/project'; export const Projects = '/projects'; @@ -35,6 +34,9 @@ export module Requests { export const Completion = '/completion'; export const CompletionResolve = '/completion/resolve'; export const CompletionAfterInsert = '/completion/afterInsert'; + export const SourceGeneratedFile = '/sourcegeneratedfile'; + export const UpdateSourceGeneratedFile = '/updatesourcegeneratedfile'; + export const SourceGeneratedFileClosed = '/sourcegeneratedfileclosed'; } export namespace WireProtocol { @@ -75,10 +77,6 @@ export interface Request extends FileBasedRequest { ApplyChangesTogether?: boolean; } -export interface GoToDefinitionRequest extends Request { - WantMetadata?: boolean; -} - export interface FindImplementationsRequest extends Request { } @@ -183,9 +181,6 @@ export interface ResourceLocation { Column: number; } -export interface GoToDefinitionResponse extends ResourceLocation { - MetadataSource?: MetadataSource; -} export interface Error { Message: string; @@ -553,6 +548,36 @@ export interface OmnisharpCompletionItem { HasAfterInsertStep: boolean; } +export interface SourceGeneratedFileInfo { + ProjectGuid: string; + DocumentGuid: string; +} + +export interface SourceGeneratedFileRequest extends SourceGeneratedFileInfo { +} + +export interface SourceGeneratedFileResponse { + Source: string; + SourceName: string; +} + +export interface UpdateSourceGeneratedFileRequest extends SourceGeneratedFileInfo { +} + +export interface UpdateSourceGeneratedFileResponse { + UpdateType: UpdateType; + Source?: string; +} + +export enum UpdateType { + Unchanged, + Deleted, + Modified +} + +export interface SourceGeneratedFileClosedRequest extends SourceGeneratedFileInfo { +} + export namespace V2 { export module Requests { @@ -571,6 +596,7 @@ export namespace V2 { export const BlockStructure = '/v2/blockstructure'; export const CodeStructure = '/v2/codestructure'; export const Highlight = '/v2/highlight'; + export const GoToDefinition = '/v2/gotodefinition'; } export interface SemanticHighlightSpan { @@ -600,6 +626,11 @@ export namespace V2 { End: Point; } + export interface Location { + FileName: string; + Range: Range; + } + export interface GetCodeActionsRequest extends Request { Selection?: Range; } @@ -870,6 +901,20 @@ export namespace V2 { walker(elements); } } + + export interface GoToDefinitionRequest extends Request { + WantMetadata?: boolean; + } + + export interface GoToDefinitionResponse { + Definitions?: Definition[]; + } + + export interface Definition { + Location: Location; + MetadataSource?: MetadataSource; + SourceGeneratedFileInfo?: SourceGeneratedFileInfo; + } } export function findNetFrameworkTargetFramework(project: MSBuildProject): TargetFramework { diff --git a/src/omnisharp/typeConversion.ts b/src/omnisharp/typeConversion.ts index 88319b5f6..6771d7544 100644 --- a/src/omnisharp/typeConversion.ts +++ b/src/omnisharp/typeConversion.ts @@ -25,6 +25,10 @@ export function toLocationFromUri(uri: vscode.Uri, location: protocol.ResourceLo return new vscode.Location(uri, position); } +export function toVscodeLocation(omnisharpLocation: protocol.V2.Location): vscode.Location { + return new vscode.Location(vscode.Uri.file(omnisharpLocation.FileName), toRange3(omnisharpLocation.Range)); +} + export function toRange(rangeLike: { Line: number; Column: number; EndLine: number; EndColumn: number; }): vscode.Range { let { Line, Column, EndLine, EndColumn } = rangeLike; return toVSCodeRange(Line, Column, EndLine, EndColumn); diff --git a/src/omnisharp/utils.ts b/src/omnisharp/utils.ts index 136b33499..6f9ca5c16 100644 --- a/src/omnisharp/utils.ts +++ b/src/omnisharp/utils.ts @@ -63,8 +63,20 @@ export async function getCodeActions(server: OmniSharpServer, request: protocol. return server.makeRequest(protocol.V2.Requests.GetCodeActions, request, token); } -export async function goToDefinition(server: OmniSharpServer, request: protocol.GoToDefinitionRequest, token: vscode.CancellationToken) { - return server.makeRequest(protocol.Requests.GoToDefinition, request); +export async function goToDefinition(server: OmniSharpServer, request: protocol.V2.GoToDefinitionRequest, token: vscode.CancellationToken) { + return server.makeRequest(protocol.V2.Requests.GoToDefinition, request, token); +} + +export async function getSourceGeneratedFile(server: OmniSharpServer, request: protocol.SourceGeneratedFileRequest, token: vscode.CancellationToken) { + return server.makeRequest(protocol.Requests.SourceGeneratedFile, request, token); +} + +export async function getUpdatedSourceGeneratedFile(server: OmniSharpServer, request: protocol.UpdateSourceGeneratedFileRequest) { + return server.makeRequest(protocol.Requests.UpdateSourceGeneratedFile, request); +} + +export async function sourceGeneratedFileClosed(server: OmniSharpServer, request: protocol.SourceGeneratedFileRequest) { + return server.makeRequest(protocol.Requests.SourceGeneratedFileClosed, request); } export async function rename(server: OmniSharpServer, request: protocol.RenameRequest, token: vscode.CancellationToken) { diff --git a/test/integrationTests/advisor.integration.test.ts b/test/integrationTests/advisor.integration.test.ts index 233472b18..c703e2ed1 100644 --- a/test/integrationTests/advisor.integration.test.ts +++ b/test/integrationTests/advisor.integration.test.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import { expect } from 'chai'; import * as path from 'path'; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; import { Advisor } from '../../src/features/diagnosticsProvider'; @@ -26,7 +26,7 @@ suite(`Advisor ${testAssetWorkspace.description}`, function () { suiteSetup(async function () { // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } @@ -84,4 +84,4 @@ suite(`Advisor ${testAssetWorkspace.description}`, function () { expect(advisor.shouldValidateFiles()).to.be.true; }); -}); \ No newline at end of file +}); diff --git a/test/integrationTests/codeActionRename.integration.test.ts b/test/integrationTests/codeActionRename.integration.test.ts index ca00ecffc..37fdfffaf 100644 --- a/test/integrationTests/codeActionRename.integration.test.ts +++ b/test/integrationTests/codeActionRename.integration.test.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import { should, expect } from 'chai'; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; import * as path from 'path'; import { assertWithPoll } from './poll'; @@ -22,7 +22,7 @@ suite(`Code Action Rename ${testAssetWorkspace.description}`, function () { should(); // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } @@ -51,4 +51,4 @@ suite(`Code Action Rename ${testAssetWorkspace.description}`, function () { await assertWithPoll(() => { }, 15 * 1000, 500, _ => expect(vscode.window.activeTextEditor.document.fileName).contains("C.cs")); }); -}); \ No newline at end of file +}); diff --git a/test/integrationTests/codeLensProvider.integration.test.ts b/test/integrationTests/codeLensProvider.integration.test.ts index f624d763e..f5bb6a832 100644 --- a/test/integrationTests/codeLensProvider.integration.test.ts +++ b/test/integrationTests/codeLensProvider.integration.test.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { should, expect } from 'chai'; -import { activateCSharpExtension } from './integrationHelpers'; +import { activateCSharpExtension, isSlnWithCsproj, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; const chai = require('chai'); @@ -18,6 +18,10 @@ suite(`CodeLensProvider: ${testAssetWorkspace.description}`, function () { let fileUri: vscode.Uri; suiteSetup(async function () { + if (isSlnWithGenerator(vscode.workspace)) { + this.skip(); + } + should(); await activateCSharpExtension(); await testAssetWorkspace.restore(); @@ -67,7 +71,7 @@ suite(`CodeLensProvider options: ${testAssetWorkspace.description}`, function () should(); // These tests only run on the slnWithCsproj solution - if (vscode.workspace.workspaceFolders[0].uri.fsPath.split(path.sep).pop() !== 'slnWithCsproj') { + if (!isSlnWithCsproj(vscode.workspace)) { this.skip(); } else { @@ -132,4 +136,4 @@ suite(`CodeLensProvider options: ${testAssetWorkspace.description}`, function () async function GetCodeLenses(fileUri: vscode.Uri, resolvedItemCount?: number) { return await vscode.commands.executeCommand("vscode.executeCodeLensProvider", fileUri, resolvedItemCount); -} \ No newline at end of file +} diff --git a/test/integrationTests/completionProvider.integration.test.ts b/test/integrationTests/completionProvider.integration.test.ts index 805e841e3..1ee358080 100644 --- a/test/integrationTests/completionProvider.integration.test.ts +++ b/test/integrationTests/completionProvider.integration.test.ts @@ -8,14 +8,14 @@ import * as vscode from 'vscode'; import testAssetWorkspace from "./testAssets/testAssetWorkspace"; import * as path from "path"; import { expect } from "chai"; -import { activateCSharpExtension, isRazorWorkspace } from "./integrationHelpers"; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from "./integrationHelpers"; suite(`${OmniSharpCompletionProvider.name}: Returns the completion items`, () => { let fileUri: vscode.Uri; suiteSetup(async function () { // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } diff --git a/test/integrationTests/definitionProvider.test.ts b/test/integrationTests/definitionProvider.test.ts index f0d3b08d8..2e027aec8 100644 --- a/test/integrationTests/definitionProvider.test.ts +++ b/test/integrationTests/definitionProvider.test.ts @@ -8,22 +8,22 @@ import CSharpDefinitionProvider from "../../src/features/definitionProvider"; import * as path from "path"; import testAssetWorkspace from "./testAssets/testAssetWorkspace"; import { expect } from "chai"; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator, restartOmniSharpServer } from './integrationHelpers'; suite(`${CSharpDefinitionProvider.name}: ${testAssetWorkspace.description}`, () => { let fileUri: vscode.Uri; suiteSetup(async function () { // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } - await activateCSharpExtension(); - await testAssetWorkspace.restore(); + const activation = await activateCSharpExtension(); + await testAssetWorkspace.restoreAndWait(activation); - let fileName = 'definition.cs'; - let projectDirectory = testAssetWorkspace.projects[0].projectDirectoryPath; + const fileName = 'definition.cs'; + const projectDirectory = testAssetWorkspace.projects[0].projectDirectoryPath; fileUri = vscode.Uri.file(path.join(projectDirectory, fileName)); await vscode.commands.executeCommand("vscode.open", fileUri); }); @@ -33,17 +33,33 @@ suite(`${CSharpDefinitionProvider.name}: ${testAssetWorkspace.description}`, () }); test("Returns the definition", async () => { - let definitionList = (await vscode.commands.executeCommand("vscode.executeDefinitionProvider", fileUri, new vscode.Position(10, 31))); + const definitionList = (await vscode.commands.executeCommand("vscode.executeDefinitionProvider", fileUri, new vscode.Position(10, 31))); expect(definitionList.length).to.be.equal(1); expect(definitionList[0]).to.exist; expect(definitionList[0].uri.path).to.contain("definition.cs"); }); - // Skipping due to https://github.com/OmniSharp/omnisharp-vscode/issues/3458 - test.skip("Returns the definition from Metadata", async () => { - let definitionList = (await vscode.commands.executeCommand("vscode.executeDefinitionProvider", fileUri, new vscode.Position(10, 25))); + test("Returns the definition from Metadata", async () => { + const omnisharpConfig = vscode.workspace.getConfiguration('omnisharp'); + await omnisharpConfig.update('enableDecompilationSupport', false, vscode.ConfigurationTarget.Global); + await restartOmniSharpServer(); + + const definitionList = (await vscode.commands.executeCommand("vscode.executeDefinitionProvider", fileUri, new vscode.Position(10, 25))); expect(definitionList.length).to.be.equal(1); expect(definitionList[0]).to.exist; expect(definitionList[0].uri.path).to.contain("[metadata] Console.cs"); }); -}); \ No newline at end of file + + test("Returns multiple definitions for partial types", async () => { + const definitionList = (await vscode.commands.executeCommand("vscode.executeDefinitionProvider", fileUri, new vscode.Position(4, 25))); + expect(definitionList.length).eq(2); + expect(definitionList[0]).to.exist; + expect(definitionList[0].uri.path).to.contain("definition.cs"); + expect(definitionList[1]).to.exist; + expect(definitionList[1].uri.path).to.contain("definition.cs"); + }); + + suiteTeardown(async () => { + await testAssetWorkspace.cleanupWorkspace(); + }); +}); diff --git a/test/integrationTests/diagnostics.integration.test.ts b/test/integrationTests/diagnostics.integration.test.ts index e518e3293..e9a8d5400 100644 --- a/test/integrationTests/diagnostics.integration.test.ts +++ b/test/integrationTests/diagnostics.integration.test.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { should, expect } from 'chai'; -import { activateCSharpExtension, isRazorWorkspace, restartOmniSharpServer } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator, restartOmniSharpServer } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; import { poll, assertWithPoll, pollDoesNotHappen } from './poll'; @@ -29,6 +29,10 @@ suite(`DiagnosticProvider: ${testAssetWorkspace.description}`, function () { suiteSetup(async function () { should(); + if (isSlnWithGenerator(vscode.workspace)) { + this.skip(); + } + await activateCSharpExtension(); await testAssetWorkspace.restore(); @@ -84,7 +88,7 @@ suite(`DiagnosticProvider: ${testAssetWorkspace.description}`, function () { should(); // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } @@ -151,7 +155,7 @@ suite(`DiagnosticProvider: ${testAssetWorkspace.description}`, function () { should(); // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } diff --git a/test/integrationTests/documentSymbolProvider.integration.test.ts b/test/integrationTests/documentSymbolProvider.integration.test.ts index 074e619bb..12daa54d5 100644 --- a/test/integrationTests/documentSymbolProvider.integration.test.ts +++ b/test/integrationTests/documentSymbolProvider.integration.test.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { should, expect } from 'chai'; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import * as integrationHelpers from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; const chai = require('chai'); @@ -21,11 +21,11 @@ suite(`DocumentSymbolProvider: ${testAssetWorkspace.description}`, function () { should(); // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (integrationHelpers.isRazorWorkspace(vscode.workspace) || integrationHelpers.isSlnWithGenerator(vscode.workspace)) { this.skip(); } - await activateCSharpExtension(); + await integrationHelpers.activateCSharpExtension(); await testAssetWorkspace.restore(); let fileName = 'documentSymbols.cs'; @@ -55,4 +55,4 @@ suite(`DocumentSymbolProvider: ${testAssetWorkspace.description}`, function () { async function GetDocumentSymbols(fileUri: vscode.Uri) { return await vscode.commands.executeCommand("vscode.executeDocumentSymbolProvider", fileUri); -} \ No newline at end of file +} diff --git a/test/integrationTests/documentationCommentAutoFormatting.integration.test.ts b/test/integrationTests/documentationCommentAutoFormatting.integration.test.ts index 9b8218f35..6be8dc7b0 100644 --- a/test/integrationTests/documentationCommentAutoFormatting.integration.test.ts +++ b/test/integrationTests/documentationCommentAutoFormatting.integration.test.ts @@ -6,7 +6,7 @@ import { expect, should } from 'chai'; import * as vscode from 'vscode'; import * as path from 'path'; -import { isRazorWorkspace } from './integrationHelpers'; +import { isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; const onTypeFormatProviderCommand = 'vscode.executeFormatOnTypeProvider'; @@ -25,7 +25,7 @@ suite(`Documentation Comment Auto Formatting: ${testAssetWorkspace.description}` suiteSetup(async function () { should(); - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { // The format-on-type provider does not run for razor files. this.skip(); } diff --git a/test/integrationTests/hoverProvider.integration.test.ts b/test/integrationTests/hoverProvider.integration.test.ts index d6c0e8588..00bbd8e40 100644 --- a/test/integrationTests/hoverProvider.integration.test.ts +++ b/test/integrationTests/hoverProvider.integration.test.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { should, expect } from 'chai'; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; export type Test = 'a' | 'b' | ['c', any]; @@ -21,7 +21,7 @@ suite(`Hover Provider: ${testAssetWorkspace.description}`, function () { should(); // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } diff --git a/test/integrationTests/implementationProvider.test.ts b/test/integrationTests/implementationProvider.test.ts index 2e14d2ae3..47d33bea3 100644 --- a/test/integrationTests/implementationProvider.test.ts +++ b/test/integrationTests/implementationProvider.test.ts @@ -8,14 +8,14 @@ import CSharpImplementationProvider from "../../src/features/implementationProvi import * as path from "path"; import testAssetWorkspace from "./testAssets/testAssetWorkspace"; import { expect } from "chai"; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; suite(`${CSharpImplementationProvider.name}: ${testAssetWorkspace.description}`, () => { let fileUri: vscode.Uri; suiteSetup(async function () { // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } @@ -36,4 +36,4 @@ suite(`${CSharpImplementationProvider.name}: ${testAssetWorkspace.description}`, let implementationList = (await vscode.commands.executeCommand("vscode.executeImplementationProvider", fileUri, new vscode.Position(4, 22))); expect(implementationList.length).to.be.equal(2); }); -}); \ No newline at end of file +}); diff --git a/test/integrationTests/integrationHelpers.ts b/test/integrationTests/integrationHelpers.ts index 1e86a0379..67acb2844 100644 --- a/test/integrationTests/integrationHelpers.ts +++ b/test/integrationTests/integrationHelpers.ts @@ -62,8 +62,20 @@ export async function restartOmniSharpServer(): Promise { } export function isRazorWorkspace(workspace: typeof vscode.workspace) { + return isGivenSln(workspace, 'BasicRazorApp2_1'); +} + +export function isSlnWithCsproj(workspace: typeof vscode.workspace) { + return isGivenSln(workspace, 'slnWithCsproj'); +} + +export function isSlnWithGenerator(workspace: typeof vscode.workspace) { + return isGivenSln(workspace, 'slnWithGenerator'); +} + +function isGivenSln(workspace: typeof vscode.workspace, expectedProjectFileName: string) { const primeWorkspace = workspace.workspaceFolders[0]; const projectFileName = primeWorkspace.uri.fsPath.split(path.sep).pop(); - return projectFileName === 'BasicRazorApp2_1'; + return projectFileName === expectedProjectFileName; } diff --git a/test/integrationTests/languageMiddleware.integration.test.ts b/test/integrationTests/languageMiddleware.integration.test.ts index 1103a2df0..b2cf26e37 100644 --- a/test/integrationTests/languageMiddleware.integration.test.ts +++ b/test/integrationTests/languageMiddleware.integration.test.ts @@ -7,7 +7,7 @@ import * as vscode from "vscode"; import * as path from "path"; import testAssetWorkspace from "./testAssets/testAssetWorkspace"; import { expect } from "chai"; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import { LanguageMiddleware, LanguageMiddlewareFeature } from "../../src/omnisharp/LanguageMiddlewareFeature"; suite(`${LanguageMiddlewareFeature.name}: ${testAssetWorkspace.description}`, () => { @@ -16,7 +16,7 @@ suite(`${LanguageMiddlewareFeature.name}: ${testAssetWorkspace.description}`, () suiteSetup(async function () { // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } @@ -125,4 +125,4 @@ class TestLanguageMiddleware implements LanguageMiddleware { } return remapped; } -} \ No newline at end of file +} diff --git a/test/integrationTests/launchConfiguration.integration.test.ts b/test/integrationTests/launchConfiguration.integration.test.ts index c44c59110..cccb2ec43 100644 --- a/test/integrationTests/launchConfiguration.integration.test.ts +++ b/test/integrationTests/launchConfiguration.integration.test.ts @@ -7,7 +7,7 @@ import * as fs from 'async-file'; import * as vscode from 'vscode'; import { should, expect } from 'chai'; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; import { poll } from './poll'; @@ -20,7 +20,7 @@ suite(`Tasks generation: ${testAssetWorkspace.description}`, function () { should(); // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } @@ -56,4 +56,4 @@ suite(`Tasks generation: ${testAssetWorkspace.description}`, function () { await debugSessionTerminated; }); -}); \ No newline at end of file +}); diff --git a/test/integrationTests/launcher.test.ts b/test/integrationTests/launcher.test.ts index e1c97c90d..62590501f 100644 --- a/test/integrationTests/launcher.test.ts +++ b/test/integrationTests/launcher.test.ts @@ -6,6 +6,7 @@ import * as vscode from 'vscode'; import { assert } from "chai"; import { resourcesToLaunchTargets, vsls, vslsTarget } from "../../src/omnisharp/launcher"; +import { isSlnWithGenerator } from './integrationHelpers'; const chai = require('chai'); chai.use(require('chai-arrays')); @@ -13,6 +14,12 @@ chai.use(require('chai-fs')); suite(`launcher:`, () => { + suiteSetup(async function () { + if (isSlnWithGenerator(vscode.workspace)) { + this.skip(); + } + }); + test(`Returns the LiveShare launch target when processing vsls resources`, () => { const testResources: vscode.Uri[] = [ vscode.Uri.parse(`${vsls}:/test.sln`), @@ -38,4 +45,4 @@ suite(`launcher:`, () => { const liveShareTarget = launchTargets.find(target => target === vslsTarget); assert.notExists(liveShareTarget, "Launch targets contained the Visual Studio Live Share target."); }); -}); \ No newline at end of file +}); diff --git a/test/integrationTests/poll.ts b/test/integrationTests/poll.ts index 97f005af7..65641a1fb 100644 --- a/test/integrationTests/poll.ts +++ b/test/integrationTests/poll.ts @@ -87,6 +87,6 @@ export async function poll( throw new Error("Polling did not succeed within the alotted duration."); } -async function sleep(ms = 0) { +export async function sleep(ms = 0) { return new Promise(r => setTimeout(r, ms)); -} \ No newline at end of file +} diff --git a/test/integrationTests/reAnalyze.integration.test.ts b/test/integrationTests/reAnalyze.integration.test.ts index f97c15066..ec86d3902 100644 --- a/test/integrationTests/reAnalyze.integration.test.ts +++ b/test/integrationTests/reAnalyze.integration.test.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { should, expect } from 'chai'; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; import { poll, assertWithPoll } from './poll'; import { EventStream } from '../../src/EventStream'; @@ -40,7 +40,7 @@ suite(`ReAnalyze: ${testAssetWorkspace.description}`, function () { should(); // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } diff --git a/test/integrationTests/referenceProvider.test.ts b/test/integrationTests/referenceProvider.test.ts index 09ca382e9..657fa6c5d 100644 --- a/test/integrationTests/referenceProvider.test.ts +++ b/test/integrationTests/referenceProvider.test.ts @@ -8,14 +8,14 @@ import OmnisharpReferenceProvider from "../../src/features/referenceProvider"; import * as path from "path"; import testAssetWorkspace from "./testAssets/testAssetWorkspace"; import { expect } from "chai"; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; suite(`${OmnisharpReferenceProvider.name}: ${testAssetWorkspace.description}`, () => { let fileUri: vscode.Uri; suiteSetup(async function () { // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } @@ -37,4 +37,4 @@ suite(`${OmnisharpReferenceProvider.name}: ${testAssetWorkspace.description}`, ( expect(referenceList.length).to.be.equal(1); expect(referenceList[0].range.start.line).to.be.equal(13); }); -}); \ No newline at end of file +}); diff --git a/test/integrationTests/semanticTokensProvider.test.ts b/test/integrationTests/semanticTokensProvider.test.ts index bfe39a190..c5457e764 100644 --- a/test/integrationTests/semanticTokensProvider.test.ts +++ b/test/integrationTests/semanticTokensProvider.test.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { should, assert } from 'chai'; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; const chai = require('chai'); @@ -53,7 +53,7 @@ suite(`SemanticTokensProvider: ${testAssetWorkspace.description}`, function () { should(); // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } diff --git a/test/integrationTests/signatureHelp.integration.test.ts b/test/integrationTests/signatureHelp.integration.test.ts index f95ce6b40..31fef65a7 100644 --- a/test/integrationTests/signatureHelp.integration.test.ts +++ b/test/integrationTests/signatureHelp.integration.test.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { expect } from 'chai'; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; const chai = require('chai'); @@ -19,7 +19,7 @@ suite(`SignatureHelp: ${testAssetWorkspace.description}`, function () { suiteSetup(async function () { // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } @@ -87,4 +87,4 @@ suite(`SignatureHelp: ${testAssetWorkspace.description}`, function () { async function GetSignatureHelp(fileUri: vscode.Uri, position: vscode.Position) { return await vscode.commands.executeCommand("vscode.executeSignatureHelpProvider", fileUri, position); -} \ No newline at end of file +} diff --git a/test/integrationTests/sourceGeneratorDefinitionProvider.test.ts b/test/integrationTests/sourceGeneratorDefinitionProvider.test.ts new file mode 100644 index 000000000..db7b6f6c0 --- /dev/null +++ b/test/integrationTests/sourceGeneratorDefinitionProvider.test.ts @@ -0,0 +1,62 @@ +import { expect } from "chai"; +import * as vscode from "vscode"; +import * as path from 'path'; +import CSharpDefinitionProvider from "../../src/features/definitionProvider"; +import { activateCSharpExtension, isSlnWithGenerator, restartOmniSharpServer } from "./integrationHelpers"; +import { assertWithPoll, sleep } from "./poll"; +import testAssetWorkspace from "./testAssets/testAssetWorkspace"; + +suite(`${CSharpDefinitionProvider.name}: ${testAssetWorkspace.description}`, () => { + let fileUri: vscode.Uri; + + suiteSetup(async function () { + // These tests don't run on the BasicRazorApp2_1 solution + if (!isSlnWithGenerator(vscode.workspace)) { + this.skip(); + } + + const activation = await activateCSharpExtension(); + await testAssetWorkspace.restoreAndWait(activation); + await vscode.commands.executeCommand("dotnet.generateAssets", 0); + await sleep(100); + const tasks = await vscode.tasks.fetchTasks(); + const task = (tasks).filter(task => task.name === 'build')[0]; + expect(task).to.not.be.undefined; + await vscode.tasks.executeTask(task); + await restartOmniSharpServer(); + + const fileName = 'GeneratorTrigger.cs'; + const projectDirectory = testAssetWorkspace.projects[0].projectDirectoryPath; + fileUri = vscode.Uri.file(path.join(projectDirectory, fileName)); + await vscode.commands.executeCommand("vscode.open", fileUri); + }); + + test("Generated file returns definitions and adds source", async () => { + if (!isSlnWithGenerator(vscode.workspace)) { + return; + } + + const textStart = new vscode.Position(11, 41); + const definitionList = (await vscode.commands.executeCommand("vscode.executeDefinitionProvider", fileUri, textStart)); + expect(definitionList.length).to.be.equal(1); + expect(definitionList[0]).to.exist; + expect(definitionList[0].uri.path).to.contain("GeneratedCode.cs"); + + const generatedCodeUri = definitionList[0].uri; + let generatedCodeDocument = await vscode.workspace.openTextDocument(generatedCodeUri); + expect(generatedCodeDocument.getText()).contains("Hello world!"); + expect(generatedCodeDocument.getText()).does.not.contain("Goodbye"); + + await vscode.commands.executeCommand('vscode.open', fileUri); + const textEdit = new vscode.WorkspaceEdit(); + textEdit.replace(fileUri, new vscode.Range(new vscode.Position(9, 27), new vscode.Position(9, 38)), "Goodbye"); + expect(await vscode.workspace.applyEdit(textEdit)).to.be.true; + + await vscode.commands.executeCommand('vscode.open', generatedCodeUri); + await assertWithPoll(() => { }, 15 * 1000, 500, _ => { + const documentText = vscode.window.activeTextEditor.document.getText(); + expect(documentText).does.not.contain("Hello world!"); + expect(documentText).contains("Goodbye"); + }); + }); +}); diff --git a/test/integrationTests/testAssets/singleCsproj/definition.cs b/test/integrationTests/testAssets/singleCsproj/definition.cs index 4ef39c5f9..eac709c0c 100644 --- a/test/integrationTests/testAssets/singleCsproj/definition.cs +++ b/test/integrationTests/testAssets/singleCsproj/definition.cs @@ -2,7 +2,7 @@ namespace Test { - public class Definition + public partial class Definition { public static string Foo { get; set; } @@ -11,4 +11,6 @@ public void MyMethod() Console.WriteLine(Foo); } } -} \ No newline at end of file + + public partial class Definition { } +} diff --git a/test/integrationTests/testAssets/slnFilterWithCsproj/.vscode/settings.json b/test/integrationTests/testAssets/slnFilterWithCsproj/.vscode/settings.json index 63e997766..9af353685 100644 --- a/test/integrationTests/testAssets/slnFilterWithCsproj/.vscode/settings.json +++ b/test/integrationTests/testAssets/slnFilterWithCsproj/.vscode/settings.json @@ -2,4 +2,4 @@ "omnisharp.defaultLaunchSolution": "SolutionFilter.slnf", "omnisharp.path": "latest", "omnisharp.enableRoslynAnalyzers": true -} \ No newline at end of file +} diff --git a/test/integrationTests/testAssets/slnFilterWithCsproj/src/app/definition.cs b/test/integrationTests/testAssets/slnFilterWithCsproj/src/app/definition.cs index 4ef39c5f9..eac709c0c 100644 --- a/test/integrationTests/testAssets/slnFilterWithCsproj/src/app/definition.cs +++ b/test/integrationTests/testAssets/slnFilterWithCsproj/src/app/definition.cs @@ -2,7 +2,7 @@ namespace Test { - public class Definition + public partial class Definition { public static string Foo { get; set; } @@ -11,4 +11,6 @@ public void MyMethod() Console.WriteLine(Foo); } } -} \ No newline at end of file + + public partial class Definition { } +} diff --git a/test/integrationTests/testAssets/slnWithCsproj.ts b/test/integrationTests/testAssets/slnWithCsproj.ts index 86aa406c8..272a249ab 100644 --- a/test/integrationTests/testAssets/slnWithCsproj.ts +++ b/test/integrationTests/testAssets/slnWithCsproj.ts @@ -9,11 +9,11 @@ let workspace: ITestAssetWorkspace = { description: "sln with several csproj's", projects: [{ relativeFilePath: "src/app/app.csproj" - },{ + }, { relativeFilePath: "src/lib/lib.csproj" - },{ + }, { relativeFilePath: "test/test.csproj" }] }; -export default workspace; \ No newline at end of file +export default workspace; diff --git a/test/integrationTests/testAssets/slnWithCsproj/a_FirstInOrder_SlnFile.sln b/test/integrationTests/testAssets/slnWithCsproj/a_FirstInOrder_SlnFile.sln index dc08b2ec7..003f74d4d 100644 --- a/test/integrationTests/testAssets/slnWithCsproj/a_FirstInOrder_SlnFile.sln +++ b/test/integrationTests/testAssets/slnWithCsproj/a_FirstInOrder_SlnFile.sln @@ -1,15 +1,16 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "test", "test\test.csproj", "{4679428B-0CA0-4228-B8C0-B676B34A1B30}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "generator", "generator\generator.csproj", "{DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -20,9 +21,6 @@ Global 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 @@ -60,9 +58,28 @@ Global {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 + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Debug|x64.ActiveCfg = Debug|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Debug|x64.Build.0 = Debug|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Debug|x86.ActiveCfg = Debug|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Debug|x86.Build.0 = Debug|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Release|Any CPU.Build.0 = Release|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Release|x64.ActiveCfg = Release|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Release|x64.Build.0 = Release|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Release|x86.ActiveCfg = Release|Any CPU + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3} = {D28FC441-C95D-47D2-8D5C-E401ABAD7C64} {717BE881-D74C-45FC-B55D-2085499E1BF8} = {D28FC441-C95D-47D2-8D5C-E401ABAD7C64} + {DCFDBE2E-0540-4A9F-AFB7-4CF1F3854440} = {D28FC441-C95D-47D2-8D5C-E401ABAD7C64} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7E415A9E-6E39-41C7-A400-051ADE582087} EndGlobalSection EndGlobal diff --git a/test/integrationTests/testAssets/slnWithCsproj/b_SecondInOrder_SlnFile.sln b/test/integrationTests/testAssets/slnWithCsproj/b_SecondInOrder_SlnFile.sln index dc08b2ec7..463a8a474 100644 --- a/test/integrationTests/testAssets/slnWithCsproj/b_SecondInOrder_SlnFile.sln +++ b/test/integrationTests/testAssets/slnWithCsproj/b_SecondInOrder_SlnFile.sln @@ -1,15 +1,16 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "test", "test\test.csproj", "{4679428B-0CA0-4228-B8C0-B676B34A1B30}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "generator", "generator\generator.csproj", "{29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -20,9 +21,6 @@ Global 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 @@ -60,9 +58,28 @@ Global {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 + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Debug|x64.ActiveCfg = Debug|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Debug|x64.Build.0 = Debug|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Debug|x86.ActiveCfg = Debug|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Debug|x86.Build.0 = Debug|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Release|Any CPU.Build.0 = Release|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Release|x64.ActiveCfg = Release|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Release|x64.Build.0 = Release|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Release|x86.ActiveCfg = Release|Any CPU + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {D36E1CC9-62CA-45A3-8BD0-6ADC2767FFB3} = {D28FC441-C95D-47D2-8D5C-E401ABAD7C64} {717BE881-D74C-45FC-B55D-2085499E1BF8} = {D28FC441-C95D-47D2-8D5C-E401ABAD7C64} + {29F9B261-D48D-4D9B-9005-FB6D3B4F9CC4} = {D28FC441-C95D-47D2-8D5C-E401ABAD7C64} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8D6D9870-8770-4AB0-8142-CC80181A8DB7} EndGlobalSection EndGlobal diff --git a/test/integrationTests/testAssets/slnWithCsproj/src/app/app.csproj b/test/integrationTests/testAssets/slnWithCsproj/src/app/app.csproj index be887dca9..5086e807c 100644 --- a/test/integrationTests/testAssets/slnWithCsproj/src/app/app.csproj +++ b/test/integrationTests/testAssets/slnWithCsproj/src/app/app.csproj @@ -4,7 +4,7 @@ Exe - netcoreapp2.1 + net5.0 diff --git a/test/integrationTests/testAssets/slnWithCsproj/src/app/definition.cs b/test/integrationTests/testAssets/slnWithCsproj/src/app/definition.cs index 4ef39c5f9..eac709c0c 100644 --- a/test/integrationTests/testAssets/slnWithCsproj/src/app/definition.cs +++ b/test/integrationTests/testAssets/slnWithCsproj/src/app/definition.cs @@ -2,7 +2,7 @@ namespace Test { - public class Definition + public partial class Definition { public static string Foo { get; set; } @@ -11,4 +11,6 @@ public void MyMethod() Console.WriteLine(Foo); } } -} \ No newline at end of file + + public partial class Definition { } +} diff --git a/test/integrationTests/testAssets/slnWithGenerator.ts b/test/integrationTests/testAssets/slnWithGenerator.ts new file mode 100644 index 000000000..f9ab1e625 --- /dev/null +++ b/test/integrationTests/testAssets/slnWithGenerator.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * 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 a source generator", + projects: [{ + relativeFilePath: "app/app.csproj" + }, { + relativeFilePath: "generator/generator.csproj" + }] +}; + +export default workspace; diff --git a/test/integrationTests/testAssets/slnWithGenerator/app/GeneratorTrigger.cs b/test/integrationTests/testAssets/slnWithGenerator/app/GeneratorTrigger.cs new file mode 100644 index 000000000..1223bc25e --- /dev/null +++ b/test/integrationTests/testAssets/slnWithGenerator/app/GeneratorTrigger.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace app +{ + public class GeneratorTrigger + { + // Generator creates GeneratedCode.S, with the same initializer. + public string S = "Hello world!"; + + public string S2 = GeneratedCode.S; + } +} diff --git a/test/integrationTests/testAssets/slnWithGenerator/app/app.csproj b/test/integrationTests/testAssets/slnWithGenerator/app/app.csproj new file mode 100644 index 000000000..b4f11bfac --- /dev/null +++ b/test/integrationTests/testAssets/slnWithGenerator/app/app.csproj @@ -0,0 +1,10 @@ + + + + + + Library + net5.0 + + + diff --git a/test/integrationTests/testAssets/slnWithGenerator/generator/MainGenerator.cs b/test/integrationTests/testAssets/slnWithGenerator/generator/MainGenerator.cs new file mode 100644 index 000000000..d3e34b01b --- /dev/null +++ b/test/integrationTests/testAssets/slnWithGenerator/generator/MainGenerator.cs @@ -0,0 +1,41 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace generator +{ + [Generator] + public class MainGenerator : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) + { + context.AddSource("GeneratedCode", @"namespace app +{ + class GeneratedCode + { + public static string S = " + ((Receiver)context.SyntaxReceiver).ConstantValue + @"; + } +}"); + } + + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(new SyntaxReceiverCreator(() => new Receiver())); + } + + private class Receiver : ISyntaxReceiver + { + internal string ConstantValue; + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (!syntaxNode.SyntaxTree.FilePath.EndsWith("GeneratorTrigger.cs") || syntaxNode is not LiteralExpressionSyntax { RawKind: (int)SyntaxKind.StringLiteralExpression } literal) + { + return; + } + + ConstantValue = literal.ToString(); + } + } + } +} diff --git a/test/integrationTests/testAssets/slnWithGenerator/generator/generator.csproj b/test/integrationTests/testAssets/slnWithGenerator/generator/generator.csproj new file mode 100644 index 000000000..e09de47f1 --- /dev/null +++ b/test/integrationTests/testAssets/slnWithGenerator/generator/generator.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.0 + true + true + 9.0 + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + diff --git a/test/integrationTests/testAssets/slnWithGenerator/slnWithGenerator.sln b/test/integrationTests/testAssets/slnWithGenerator/slnWithGenerator.sln new file mode 100644 index 000000000..213fc3b43 --- /dev/null +++ b/test/integrationTests/testAssets/slnWithGenerator/slnWithGenerator.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.6.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "generator", "generator\generator.csproj", "{7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app", "app\app.csproj", "{3C53CC35-407C-44EC-ACB0-31E44155142D}" +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 + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Debug|x64.ActiveCfg = Debug|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Debug|x64.Build.0 = Debug|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Debug|x86.ActiveCfg = Debug|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Debug|x86.Build.0 = Debug|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Release|Any CPU.Build.0 = Release|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Release|x64.ActiveCfg = Release|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Release|x64.Build.0 = Release|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Release|x86.ActiveCfg = Release|Any CPU + {7E0D7281-5CE1-4DE6-901D-272F7A1BA4E6}.Release|x86.Build.0 = Release|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Debug|x64.ActiveCfg = Debug|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Debug|x64.Build.0 = Debug|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Debug|x86.ActiveCfg = Debug|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Debug|x86.Build.0 = Debug|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Release|Any CPU.Build.0 = Release|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Release|x64.ActiveCfg = Release|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Release|x64.Build.0 = Release|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Release|x86.ActiveCfg = Release|Any CPU + {3C53CC35-407C-44EC-ACB0-31E44155142D}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/test/integrationTests/testAssets/testAssetWorkspace.ts b/test/integrationTests/testAssets/testAssetWorkspace.ts index 8622b313b..808bbd077 100644 --- a/test/integrationTests/testAssets/testAssetWorkspace.ts +++ b/test/integrationTests/testAssets/testAssetWorkspace.ts @@ -12,12 +12,14 @@ import singleCsproj from './singleCsproj'; import slnWithCsproj from './slnWithCsproj'; import slnFilterWithCsproj from './slnFilterWithCsproj'; import BasicRazorApp2_1 from './BasicRazorApp2_1'; +import slnWithGenerator from './slnWithGenerator'; const testAssetWorkspaces: { [x: string]: ITestAssetWorkspace } = { singleCsproj, slnWithCsproj, slnFilterWithCsproj, - BasicRazorApp2_1 + BasicRazorApp2_1, + slnWithGenerator }; const workspaceName = vscode.workspace.workspaceFolders[0].uri.fsPath @@ -26,4 +28,4 @@ const workspaceName = vscode.workspace.workspaceFolders[0].uri.fsPath const activeTestAssetWorkspace = new TestAssetWorkspace(testAssetWorkspaces[workspaceName]); -export default activeTestAssetWorkspace; \ No newline at end of file +export default activeTestAssetWorkspace; diff --git a/test/integrationTests/virtualDocumentTracker.integration.test.ts b/test/integrationTests/virtualDocumentTracker.integration.test.ts index a2a231d42..85ec44cc8 100644 --- a/test/integrationTests/virtualDocumentTracker.integration.test.ts +++ b/test/integrationTests/virtualDocumentTracker.integration.test.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import { should, assert } from 'chai'; -import { activateCSharpExtension } from './integrationHelpers'; +import { activateCSharpExtension, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; import { IDisposable } from '../../src/Disposable'; @@ -20,6 +20,9 @@ suite(`Virtual Document Tracking ${testAssetWorkspace.description}`, function () let virtualUri: vscode.Uri; suiteSetup(async function () { + if (isSlnWithGenerator(vscode.workspace)) { + this.skip(); + } should(); const virtualCSharpDocumentProvider = new VirtualCSharpDocumentProvider(); @@ -31,6 +34,10 @@ suite(`Virtual Document Tracking ${testAssetWorkspace.description}`, function () }); suiteTeardown(async () => { + if (isSlnWithGenerator(vscode.workspace)) { + return; + } + await testAssetWorkspace.cleanupWorkspace(); virtualDocumentRegistration.dispose(); }); @@ -54,4 +61,4 @@ class VirtualCSharpDocumentProvider implements vscode.TextDocumentContentProvide }`; } -} \ No newline at end of file +} diff --git a/test/integrationTests/workspaceSymbolProvider.integration.test.ts b/test/integrationTests/workspaceSymbolProvider.integration.test.ts index 362d85a5d..b64052d8d 100644 --- a/test/integrationTests/workspaceSymbolProvider.integration.test.ts +++ b/test/integrationTests/workspaceSymbolProvider.integration.test.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import { expect } from 'chai'; -import { activateCSharpExtension, isRazorWorkspace } from './integrationHelpers'; +import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; const chai = require('chai'); chai.use(require('chai-arrays')); @@ -16,7 +16,7 @@ suite(`WorkspaceSymbolProvider: ${testAssetWorkspace.description}`, function () suiteSetup(async function () { // These tests don't run on the BasicRazorApp2_1 solution - if (isRazorWorkspace(vscode.workspace)) { + if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) { this.skip(); } @@ -54,4 +54,4 @@ suite(`WorkspaceSymbolProvider: ${testAssetWorkspace.description}`, function () async function GetWorkspaceSymbols(filter: string) { return await vscode.commands.executeCommand("vscode.executeWorkspaceSymbolProvider", filter); -} \ No newline at end of file +} diff --git a/test/runIntegrationTests.ts b/test/runIntegrationTests.ts index f68770417..1257cea72 100644 --- a/test/runIntegrationTests.ts +++ b/test/runIntegrationTests.ts @@ -6,6 +6,14 @@ import * as path from 'path'; import { runTests } from 'vscode-test'; +import { execChildProcess } from '../src/common'; + +function getSln(workspacePath: string): string | undefined { + if (workspacePath.endsWith("slnWithGenerator")) { + return "slnWithGenerator.sln"; + } + return undefined; +} async function main() { try { @@ -18,11 +26,23 @@ async function main() { const extensionTestsPath = path.resolve(__dirname, './integrationTests/index'); // The integration tests expect that the workspace to run the - // tests against is set in an evironment variable. + // tests against is set in an environment variable. const workspacePath = process.env.CODE_TESTS_WORKSPACE; + if (!workspacePath) { + console.error(`Empty workspace path`); + process.exit(-1); + } + console.log(`workspace path = '${workspacePath}'`); + const sln = getSln(workspacePath); + if (sln) { + // Run a build before the tests, to ensure that source generators are set up correctly + const dotnetPath = path.join(process.env.DOTNET_ROOT, 'dotnet'); + await execChildProcess(`${dotnetPath} build ${sln}`, workspacePath); + } + // Download VS Code, unzip it and run the integration test await runTests({ extensionDevelopmentPath, extensionTestsPath, launchArgs: [workspacePath, '-n', '--verbose'], extensionTestsEnv: process.env }); } catch (err) { @@ -32,4 +52,4 @@ async function main() { } } -main(); \ No newline at end of file +main();