Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable test codelens when devkit is enabled #69119

Merged
merged 2 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System.Composition;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.Extensions.Logging;
using Roslyn.Utilities;

Expand All @@ -12,12 +13,15 @@ namespace Microsoft.CodeAnalysis.LanguageServer;
[Export, Shared]
internal class ServerConfigurationFactory
{
private readonly IGlobalOptionService _globalOptionService;

private ServerConfiguration? _serverConfiguration;

[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public ServerConfigurationFactory()
public ServerConfigurationFactory(IGlobalOptionService globalOptionService)
{
_globalOptionService = globalOptionService;
}

[Export(typeof(ServerConfiguration))]
Expand All @@ -27,6 +31,13 @@ public void InitializeConfiguration(ServerConfiguration serverConfiguration)
{
Contract.ThrowIfFalse(_serverConfiguration == null);
_serverConfiguration = serverConfiguration;

// Update any other global options based on the configuration the server was started with.

// Use the SharedDependenciesPath option as a proxy for whether or not devkit is running.
var isDevkitEnabled = !string.IsNullOrEmpty(serverConfiguration.SharedDependenciesPath);
// Set the standalone option so other features know that devkit is not running.
dibarbet marked this conversation as resolved.
Show resolved Hide resolved
_globalOptionService.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, isDevkitEnabled);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.CodeAnalysis.Features.Testing;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.Handler.Testing;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
Expand All @@ -27,10 +28,13 @@ internal sealed class CodeLensHandler : ILspServiceDocumentRequestHandler<LSP.Co
{
public const string RunTestsCommandIdentifier = "dotnet.test.run";

private readonly IGlobalOptionService _globalOptionService;

[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CodeLensHandler()
public CodeLensHandler(IGlobalOptionService globalOptionService)
{
_globalOptionService = globalOptionService;
}

public bool MutatesSolutionState => false;
Expand Down Expand Up @@ -70,7 +74,11 @@ public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeLensParams r
codeLenses.Add(codeLens);
}

AddTestCodeLens(codeLenses, members, document, text, request.TextDocument);
if (!_globalOptionService.GetOption(LspOptionsStorage.LspUsingDevkitFeatures))
{
// Only return test codelenses if we're not using devkit.
AddTestCodeLens(codeLenses, members, document, text, request.TextDocument);
}

return codeLenses.ToArray();
}
Expand Down
8 changes: 8 additions & 0 deletions src/Features/LanguageServer/Protocol/LspOptionsStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,13 @@ internal sealed class LspOptionsStorage

// Flag is defined in VisualStudio\Core\Def\PackageRegistration.pkgdef.
public static readonly Option2<bool> LspSemanticTokensFeatureFlag = new("dotnet_enable_lsp_semantic_tokens", defaultValue: false);

/// <summary>
/// This flag is turned on when the C# devkit is installed.
/// This can cause certain LSP features to behave differently, for example we avoid returning test code lenses when devkit is running.
///
/// This flag is not user visible.
/// </summary>
dibarbet marked this conversation as resolved.
Show resolved Hide resolved
public static readonly Option2<bool> LspUsingDevkitFeatures = new("dotnet_lsp_using_devkit", defaultValue: true);
dibarbet marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,20 @@ private protected static async Task VerifyTestCodeLensAsync(TestLspServer testLs
Assert.Single(matchingCodeLenses);
Assert.Equal(commandTitle, matchingCodeLenses.Single().Command!.Title);
}

private protected static async Task VerifyTestCodeLensMissingAsync(TestLspServer testLspServer)
{
var expectedCodeLens = testLspServer.GetLocations("codeLens").Single();

var textDocument = CreateTextDocumentIdentifier(testLspServer.GetCurrentSolution().Projects.Single().Documents.Single().GetURI());
var codeLensParams = new LSP.CodeLensParams
{
TextDocument = textDocument
};

var actualCodeLenses = await testLspServer.ExecuteRequestAsync<LSP.CodeLensParams, LSP.CodeLens[]?>(LSP.Methods.TextDocumentCodeLensName, codeLensParams, CancellationToken.None);
AssertEx.NotNull(actualCodeLenses);
Assert.NotEmpty(actualCodeLenses);
Assert.All(actualCodeLenses, actualCodeLens => Assert.NotEqual(CodeLensHandler.RunTestsCommandIdentifier, actualCodeLens.Command?.CommandIdentifier));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,14 @@ class A
}
}
";
await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, CapabilitiesWithVSExtensions);
await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new InitializationOptions
{
ClientCapabilities = CapabilitiesWithVSExtensions,
OptionUpdater = (globalOptions) =>
{
globalOptions.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, false);
}
});
await VerifyTestCodeLensAsync(testLspServer, FeaturesResources.Run_Test);
}

Expand All @@ -280,7 +287,47 @@ public void M()
}
}
";
await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, CapabilitiesWithVSExtensions);
await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new InitializationOptions
{
ClientCapabilities = CapabilitiesWithVSExtensions,
OptionUpdater = (globalOptions) =>
{
globalOptions.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, false);
}
});
await VerifyTestCodeLensAsync(testLspServer, FeaturesResources.Run_All_Tests);
}

[Theory, CombinatorialData]
public async Task TestDoesNotHaveTestCommandWhenDisabledAsync(bool mutatingLspWorkspace)
{
var markup =
@"using System;
namespace Xunit
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class FactAttribute : Attribute { }
}
namespace Test
{
using Xunit;
class A
{
[Fact]
public void {|codeLens:M|}()
{
}
}
}
";
await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new InitializationOptions
{
ClientCapabilities = CapabilitiesWithVSExtensions,
OptionUpdater = (globalOptions) =>
{
globalOptions.SetGlobalOption(LspOptionsStorage.LspUsingDevkitFeatures, true);
}
});
await VerifyTestCodeLensMissingAsync(testLspServer);
}
}