Skip to content

Commit 8e7ed18

Browse files
committed
Test
1 parent 9bfe55b commit 8e7ed18

File tree

2 files changed

+84
-14
lines changed

2 files changed

+84
-14
lines changed

src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics;
67
using System.Linq;
78
using System.Threading;
89
using System.Threading.Tasks;
@@ -18,6 +19,7 @@
1819
using Microsoft.CodeAnalysis.Razor.Tooltip;
1920
using Microsoft.CodeAnalysis.Testing;
2021
using Microsoft.CodeAnalysis.Text;
22+
using Roslyn.Test.Utilities;
2123
using Xunit;
2224
using Xunit.Abstractions;
2325
using Xunit.Sdk;
@@ -214,6 +216,68 @@ async Task FooAsync()
214216
Assert.True(expectedSourceText.ContentEquals(actualSourceText));
215217
}
216218

219+
[Fact]
220+
public async Task ResolveAsync_CSharp_RemapAndFormatsTextEdit_UsingDirective()
221+
{
222+
// Arrange
223+
TestCode input =
224+
"""
225+
@{
226+
Task FooAsync()
227+
{
228+
String$$
229+
}
230+
}
231+
""";
232+
233+
// Admittedly the result here is not perfect, but only because our tests don't implement the full LSP editor logic. The key thing
234+
// is the addition of the using directive.
235+
var expectedSourceText = SourceText.From(
236+
"""
237+
@using System.Text
238+
@{
239+
Task FooAsync()
240+
{
241+
String
242+
}
243+
}
244+
""");
245+
246+
var codeDocument = CreateCodeDocument(input.Text, filePath: "C:/path/to/file.razor");
247+
// Roslyn won't send unimported types if SupportsVisualStudioExtensions is true
248+
await using var csharpServer = await CreateCSharpServerAsync(codeDocument, supportsVisualStudioExtensions: false);
249+
250+
var clientConnection = CreateClientConnectionForResolve(csharpServer);
251+
var documentContextFactory = new TestDocumentContextFactory("C:/path/to/file.razor", codeDocument);
252+
var optionsMonitor = TestRazorLSPOptionsMonitor.Create();
253+
var formattingService = await _lazyFormattingService.GetValueAsync(DisposalToken);
254+
var resolver = new DelegatedCompletionItemResolver(documentContextFactory, formattingService, DocumentMappingService, optionsMonitor, clientConnection, LoggerFactory);
255+
var containingCompletionList = await GetCompletionListAndOriginalParamsAsync(input.Position, codeDocument, csharpServer);
256+
257+
var sw = Stopwatch.StartNew();
258+
VSInternalCompletionItem item;
259+
while ((item = containingCompletionList.Items.FirstOrDefault(item => item.Label == "StringBuilder")) == null)
260+
{
261+
Assert.True(sw.Elapsed < TimeSpan.FromSeconds(5), "Failed to resolve unimported completion item after 5 second.");
262+
263+
// Roslyn only computes unimported types in the background, and we have no access to its internal workings to wait for it to be
264+
// finished, so we just have to delay and ask for completion items again.
265+
await Task.Delay(100, DisposalToken);
266+
containingCompletionList = await GetCompletionListAndOriginalParamsAsync(input.Position, codeDocument, csharpServer);
267+
}
268+
269+
Assert.NotNull(item);
270+
271+
var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, containingCompletionList.Data);
272+
var resolvedItem = await resolver.ResolveAsync(
273+
item, containingCompletionList, originalRequestContext, s_clientCapabilities, _componentAvailabilityService, DisposalToken);
274+
275+
var originalSourceText = SourceText.From(input.Text);
276+
var textChange = originalSourceText.GetTextChange(resolvedItem.AdditionalTextEdits.Single());
277+
var actualSourceText = originalSourceText.WithChanges(textChange);
278+
AssertEx.EqualOrDiff(expectedSourceText.ToString(), actualSourceText.ToString());
279+
}
280+
217281
[Fact]
218282
public async Task ResolveAsync_Html_Resolves()
219283
{
@@ -246,15 +310,14 @@ private async Task<VSInternalCompletionItem> ResolveCompletionItemAsync(string c
246310
{
247311
TestFileMarkupParser.GetPosition(content, out var documentContent, out var cursorPosition);
248312
var codeDocument = CreateCodeDocument(documentContent, filePath: "C:/path/to/file.razor");
249-
await using var csharpServer = await CreateCSharpServerAsync(codeDocument);
313+
await using var csharpServer = await CreateCSharpServerAsync(codeDocument, supportsVisualStudioExtensions: true);
250314

251315
var clientConnection = CreateClientConnectionForResolve(csharpServer);
252316
var documentContextFactory = new TestDocumentContextFactory("C:/path/to/file.razor", codeDocument);
253317
var optionsMonitor = TestRazorLSPOptionsMonitor.Create();
254318
var formattingService = await _lazyFormattingService.GetValueAsync(DisposalToken);
255319
var resolver = new DelegatedCompletionItemResolver(documentContextFactory, formattingService, DocumentMappingService, optionsMonitor, clientConnection, LoggerFactory);
256-
var (containingCompletionList, csharpCompletionParams) = await GetCompletionListAndOriginalParamsAsync(
257-
cursorPosition, codeDocument, csharpServer);
320+
var containingCompletionList = await GetCompletionListAndOriginalParamsAsync(cursorPosition, codeDocument, csharpServer);
258321

259322
var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, containingCompletionList.Data);
260323
var item = containingCompletionList.Items.FirstOrDefault(item => item.Label == itemToResolve);
@@ -270,7 +333,7 @@ private async Task<VSInternalCompletionItem> ResolveCompletionItemAsync(string c
270333
return resolvedItem;
271334
}
272335

273-
private async Task<CSharpTestLspServer> CreateCSharpServerAsync(RazorCodeDocument codeDocument)
336+
private async Task<CSharpTestLspServer> CreateCSharpServerAsync(RazorCodeDocument codeDocument, bool supportsVisualStudioExtensions)
274337
{
275338
var csharpSourceText = codeDocument.GetCSharpSourceText();
276339
var csharpDocumentUri = new Uri("C:/path/to/file.razor__virtual.g.cs");
@@ -283,32 +346,33 @@ private async Task<CSharpTestLspServer> CreateCSharpServerAsync(RazorCodeDocumen
283346
}
284347
};
285348

349+
var capabilitiesUpdater = (VSInternalClientCapabilities c) =>
350+
{
351+
c.SupportsVisualStudioExtensions = supportsVisualStudioExtensions;
352+
};
353+
286354
// Don't declare this with an 'await using'. The caller owns the lifetime of this C# LSP server.
287355
var csharpServer = await CSharpTestLspServerHelpers.CreateCSharpLspServerAsync(
288-
csharpSourceText, csharpDocumentUri, serverCapabilities, DisposalToken);
356+
csharpSourceText, csharpDocumentUri, serverCapabilities, capabilitiesUpdater, DisposalToken);
289357

290358
await csharpServer.OpenDocumentAsync(csharpDocumentUri, csharpSourceText.ToString(), DisposalToken);
291359

292360
return csharpServer;
293361
}
294362

295-
private async Task<(RazorVSInternalCompletionList, DelegatedCompletionParams)> GetCompletionListAndOriginalParamsAsync(
363+
private async Task<RazorVSInternalCompletionList> GetCompletionListAndOriginalParamsAsync(
296364
int cursorPosition,
297365
RazorCodeDocument codeDocument,
298366
CSharpTestLspServer csharpServer)
299367
{
300368
var completionContext = new VSInternalCompletionContext() { TriggerKind = CompletionTriggerKind.Invoked };
301369
var documentContext = TestDocumentContext.Create("C:/path/to/file.razor", codeDocument);
302370

303-
DelegatedCompletionParams? delegatedParams = null;
304-
var clientConnection = CreateClientConnectionForCompletion(csharpServer, processParams: @params =>
305-
{
306-
delegatedParams = @params;
307-
});
371+
var clientConnection = CreateClientConnectionForCompletion(csharpServer);
308372

309373
var provider = CreateDelegatedCompletionListProvider(clientConnection);
310374

311-
var completionList = await provider.GetCompletionListAsync(
375+
return await provider.GetCompletionListAsync(
312376
codeDocument,
313377
cursorPosition,
314378
completionContext,
@@ -317,7 +381,5 @@ private async Task<CSharpTestLspServer> CreateCSharpServerAsync(RazorCodeDocumen
317381
s_defaultRazorCompletionOptions,
318382
correlationId: Guid.Empty,
319383
cancellationToken: DisposalToken);
320-
321-
return (completionList, delegatedParams);
322384
}
323385
}

src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/CSharpTestLspServerHelpers.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ public static Task<CSharpTestLspServer> CreateCSharpLspServerAsync(
3232
CancellationToken cancellationToken) =>
3333
CreateCSharpLspServerAsync(csharpSourceText, csharpDocumentUri, serverCapabilities, new EmptyMappingService(), capabilitiesUpdater: null, cancellationToken);
3434

35+
public static Task<CSharpTestLspServer> CreateCSharpLspServerAsync(
36+
SourceText csharpSourceText,
37+
Uri csharpDocumentUri,
38+
VSInternalServerCapabilities serverCapabilities,
39+
Action<VSInternalClientCapabilities> capabilitiesUpdater,
40+
CancellationToken cancellationToken) =>
41+
CreateCSharpLspServerAsync(csharpSourceText, csharpDocumentUri, serverCapabilities, new EmptyMappingService(), capabilitiesUpdater, cancellationToken);
42+
3543
public static Task<CSharpTestLspServer> CreateCSharpLspServerAsync(
3644
SourceText csharpSourceText,
3745
Uri csharpDocumentUri,

0 commit comments

Comments
 (0)