Skip to content

Commit 39da7af

Browse files
authored
Merge pull request #7538 from dibarbet/navigate_inside_metadata_tests
Add tests for navigation from inside metadata as source workspace
2 parents 719806f + 869ee42 commit 39da7af

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

test/lsptoolshost/integrationTests/gotoDefinition.integration.test.ts

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66
import * as vscode from 'vscode';
77
import * as path from 'path';
88
import testAssetWorkspace from './testAssets/testAssetWorkspace';
9-
import { activateCSharpExtension, closeAllEditorsAsync, openFileInWorkspaceAsync } from './integrationHelpers';
9+
import {
10+
activateCSharpExtension,
11+
closeAllEditorsAsync,
12+
findRangeOfString,
13+
openFileInWorkspaceAsync,
14+
} from './integrationHelpers';
1015
import { describe, beforeAll, beforeEach, afterAll, test, expect, afterEach } from '@jest/globals';
1116

1217
describe(`[${testAssetWorkspace.description}] Test Go To Definition`, () => {
@@ -79,6 +84,50 @@ describe(`[${testAssetWorkspace.description}] Test Go To Definition`, () => {
7984
);
8085
});
8186

87+
test('Navigates from definition in decompiled source goes to decompiled source', async () => {
88+
await openFileInWorkspaceAsync(path.join('test', 'UnitTest1.cs'));
89+
90+
// Get definitions
91+
const requestPosition = new vscode.Position(13, 9);
92+
const definitionList = <vscode.Location[]>(
93+
await vscode.commands.executeCommand(
94+
'vscode.executeDefinitionProvider',
95+
vscode.window.activeTextEditor!.document.uri,
96+
requestPosition
97+
)
98+
);
99+
expect(definitionList.length).toEqual(1);
100+
const definitionPath = definitionList[0].uri;
101+
expect(definitionPath.fsPath).toContain('FactAttribute.cs');
102+
103+
// Navigate
104+
await navigate(requestPosition, definitionList, 'FactAttribute.cs');
105+
expect(vscode.window.activeTextEditor?.document.getText()).toContain(
106+
'// Decompiled with ICSharpCode.Decompiler'
107+
);
108+
109+
// Get definitions from inside FactAttribute.cs
110+
// Rather than hardcoding a location, we find the location by searching the document as different SDKs may have different versions of the source.
111+
const rangeOfDefinition = findRangeOfString(vscode.window.activeTextEditor!, 'XunitTestCaseDiscoverer')[0];
112+
const attributeUsageDefinition = <vscode.Location[]>(
113+
await vscode.commands.executeCommand(
114+
'vscode.executeDefinitionProvider',
115+
vscode.window.activeTextEditor!.document.uri,
116+
rangeOfDefinition.start
117+
)
118+
);
119+
120+
expect(attributeUsageDefinition.length).toEqual(1);
121+
const attributeDefinitionPath = attributeUsageDefinition[0].uri;
122+
expect(attributeDefinitionPath.fsPath).toContain('XunitTestCaseDiscovererAttribute.cs');
123+
124+
// Navigate
125+
await navigate(rangeOfDefinition.start, attributeUsageDefinition, 'XunitTestCaseDiscovererAttribute.cs');
126+
expect(vscode.window.activeTextEditor?.document.getText()).toContain(
127+
'// Decompiled with ICSharpCode.Decompiler'
128+
);
129+
});
130+
82131
test('Navigates to definition in metadata as source', async () => {
83132
// Get definitions
84133
const requestPosition = new vscode.Position(10, 25);
@@ -100,6 +149,48 @@ describe(`[${testAssetWorkspace.description}] Test Go To Definition`, () => {
100149
);
101150
});
102151

152+
test('Navigates to definition from inside metadata as source', async () => {
153+
// Get definitions
154+
const requestPosition = new vscode.Position(10, 25);
155+
const definitionList = <vscode.Location[]>(
156+
await vscode.commands.executeCommand(
157+
'vscode.executeDefinitionProvider',
158+
vscode.window.activeTextEditor!.document.uri,
159+
requestPosition
160+
)
161+
);
162+
expect(definitionList.length).toEqual(1);
163+
const definitionPath = definitionList[0].uri;
164+
expect(definitionPath.fsPath).toContain('Console.cs');
165+
166+
// Navigate
167+
await navigate(requestPosition, definitionList, 'Console.cs');
168+
expect(vscode.window.activeTextEditor?.document.getText()).not.toContain(
169+
'// Decompiled with ICSharpCode.Decompiler'
170+
);
171+
172+
// Get definitions from inside Console.cs
173+
// Rather than hardcoding a location, we find the location by searching the document as different SDKs may have different versions of the source.
174+
const rangeOfDefinition = findRangeOfString(vscode.window.activeTextEditor!, 'ConsoleColor ForegroundColor')[0];
175+
const consoleColorDefinition = <vscode.Location[]>(
176+
await vscode.commands.executeCommand(
177+
'vscode.executeDefinitionProvider',
178+
vscode.window.activeTextEditor!.document.uri,
179+
rangeOfDefinition.start
180+
)
181+
);
182+
183+
expect(consoleColorDefinition.length).toEqual(1);
184+
const consoleColorDefinitionPath = consoleColorDefinition[0].uri;
185+
expect(consoleColorDefinitionPath.fsPath).toContain('ConsoleColor.cs');
186+
187+
// Navigate
188+
await navigate(rangeOfDefinition.start, consoleColorDefinition, 'ConsoleColor.cs');
189+
expect(vscode.window.activeTextEditor?.document.getText()).not.toContain(
190+
'// Decompiled with ICSharpCode.Decompiler'
191+
);
192+
});
193+
103194
test('Returns multiple definitions for partial types', async () => {
104195
const definitionList = <vscode.Location[]>(
105196
await vscode.commands.executeCommand(

test/lsptoolshost/integrationTests/integrationHelpers.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@ export function sortLocations(locations: vscode.Location[]): vscode.Location[] {
120120
});
121121
}
122122

123+
export function findRangeOfString(editor: vscode.TextEditor, stringToFind: string): vscode.Range[] {
124+
const text = editor.document.getText();
125+
const matches = [...text.matchAll(new RegExp(stringToFind, 'gm'))];
126+
const ranges = matches.map((match) => {
127+
const startPos = editor.document.positionAt(match.index!);
128+
const endPos = editor.document.positionAt(match.index! + stringToFind.length);
129+
return new vscode.Range(startPos, endPos);
130+
});
131+
return ranges;
132+
}
133+
123134
function isGivenSln(workspace: typeof vscode.workspace, expectedProjectFileName: string) {
124135
const primeWorkspace = workspace.workspaceFolders![0];
125136
const projectFileName = primeWorkspace.uri.fsPath.split(path.sep).pop();

0 commit comments

Comments
 (0)