From 97c54a23f17cdc2807fc3ff2d3ce74572e55e4e6 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Thu, 17 Dec 2020 13:43:55 -0800 Subject: [PATCH] Add integration test support for LSP based editor --- eng/build.ps1 | 9 +++ src/Compilers/Test/Core/Traits/Traits.cs | 1 + src/Tools/Source/RunTests/ITestExecutor.cs | 8 +-- src/Tools/Source/RunTests/Options.cs | 18 ++---- .../Source/RunTests/ProcessTestExecutor.cs | 20 ++----- src/Tools/Source/RunTests/Program.cs | 4 +- .../CSharp/CSharpGoToDefinition.cs | 10 ++-- .../CSharp/CSharpGoToImplementation.cs | 14 ++--- .../CSharp/CSharpSourceGenerators.cs | 2 +- .../LspGoToDefinition.cs | 55 +++++++++++++++++++ .../VisualBasic/BasicGoToDefinition.cs | 6 +- .../VisualBasic/BasicGoToImplementation.cs | 4 +- .../OutOfProcess/Editor_OutOfProc.cs | 14 +++-- .../VisualStudioInstanceFactory.cs | 3 + 14 files changed, 109 insertions(+), 59 deletions(-) create mode 100644 src/VisualStudio/IntegrationTest/IntegrationTests/LanguageServerProtocol/LspGoToDefinition.cs diff --git a/eng/build.ps1 b/eng/build.ps1 index ba7193570a317..10316a7290981 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -44,6 +44,7 @@ param ( [switch]$warnAsError = $false, [switch]$sourceBuild = $false, [switch]$oop64bit = $true, + [switch]$lspEditor = $false, # official build settings [string]$officialBuildId = "", @@ -365,6 +366,13 @@ function TestUsingRunTests() { $args += " --sequential" $args += " --include '\.IntegrationTests'" $args += " --include 'Microsoft.CodeAnalysis.Workspaces.MSBuild.UnitTests'" + + if ($lspEditor) { + $args += " --testfilter FullyQualifiedName~Roslyn.VisualStudio.IntegrationTests.LanguageServerProtocol|Editor=LanguageServerProtocol" + } + else { + $args += " --testfilter FullyQualifiedName!~Roslyn.VisualStudio.IntegrationTests.LanguageServerProtocol" + } } if (-not $ci -and -not $testVsi) { @@ -538,6 +546,7 @@ function Setup-IntegrationTestRun() { } $env:ROSLYN_OOP64BIT = "$oop64bit" + $env:ROSLYN_LSPEDITOR = "$lspEditor" } function Prepare-TempDir() { diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs index e3dab710c0bab..91d7d38d854cb 100644 --- a/src/Compilers/Test/Core/Traits/Traits.cs +++ b/src/Compilers/Test/Core/Traits/Traits.cs @@ -14,6 +14,7 @@ public static class Editors public const string KeyProcessors = nameof(KeyProcessors); public const string KeyProcessorProviders = nameof(KeyProcessorProviders); public const string Preview = nameof(Preview); + public const string LanguageServerProtocol = nameof(LanguageServerProtocol); } public const string Feature = nameof(Feature); diff --git a/src/Tools/Source/RunTests/ITestExecutor.cs b/src/Tools/Source/RunTests/ITestExecutor.cs index 3f08b497b0e90..b6a774a935033 100644 --- a/src/Tools/Source/RunTests/ITestExecutor.cs +++ b/src/Tools/Source/RunTests/ITestExecutor.cs @@ -13,18 +13,16 @@ internal readonly struct TestExecutionOptions internal string DotnetFilePath { get; } internal ProcDumpInfo? ProcDumpInfo { get; } internal string TestResultsDirectory { get; } - internal string? Trait { get; } - internal string? NoTrait { get; } + internal string? TestFilter { get; } internal bool IncludeHtml { get; } internal bool Retry { get; } - internal TestExecutionOptions(string dotnetFilePath, ProcDumpInfo? procDumpInfo, string testResultsDirectory, string? trait, string? noTrait, bool includeHtml, bool retry) + internal TestExecutionOptions(string dotnetFilePath, ProcDumpInfo? procDumpInfo, string testResultsDirectory, string? testFilter, bool includeHtml, bool retry) { DotnetFilePath = dotnetFilePath; ProcDumpInfo = procDumpInfo; TestResultsDirectory = testResultsDirectory; - Trait = trait; - NoTrait = noTrait; + TestFilter = testFilter; IncludeHtml = includeHtml; Retry = retry; } diff --git a/src/Tools/Source/RunTests/Options.cs b/src/Tools/Source/RunTests/Options.cs index 4f476cde6d13f..69a931703463f 100644 --- a/src/Tools/Source/RunTests/Options.cs +++ b/src/Tools/Source/RunTests/Options.cs @@ -34,14 +34,9 @@ internal class Options public Display Display { get; set; } /// - /// Trait string to pass to xunit. + /// Filter string to pass to xunit. /// - public string? Trait { get; set; } - - /// - /// The no-trait string to pass to xunit. - /// - public string? NoTrait { get; set; } + public string? TestFilter { get; set; } public string Configuration { get; set; } @@ -125,8 +120,7 @@ public Options( var excludeFilter = new List(); var sequential = false; var retry = false; - string? traits = null; - string? noTraits = null; + string? testFilter = null; int? timeout = null; string? resultFileDirectory = null; string? logFileDirectory = null; @@ -144,8 +138,7 @@ public Options( { "platform=", "Platform to test: x86 or x64", (string s) => platform = s }, { "html", "Include HTML file output", o => includeHtml = o is object }, { "sequential", "Run tests sequentially", o => sequential = o is object }, - { "traits=", "xUnit traits to include (semicolon delimited)", (string s) => traits = s }, - { "notraits=", "xUnit traits to exclude (semicolon delimited)", (string s) => noTraits = s }, + { "testfilter=", "xUnit string to pass to --filter, e.g. FullyQualifiedName~TestClass1|Category=CategoryA", (string s) => testFilter = s }, { "timeout=", "Minute timeout to limit the tests to", (int i) => timeout = i }, { "out=", "Test result file directory", (string s) => resultFileDirectory = s }, { "logs=", "Log file directory", (string s) => logFileDirectory = s }, @@ -225,8 +218,7 @@ public Options( CollectDumps = collectDumps, Sequential = sequential, IncludeHtml = includeHtml, - Trait = traits, - NoTrait = noTraits, + TestFilter = testFilter, Timeout = timeout is { } t ? TimeSpan.FromMinutes(t) : null, Retry = retry, }; diff --git a/src/Tools/Source/RunTests/ProcessTestExecutor.cs b/src/Tools/Source/RunTests/ProcessTestExecutor.cs index beea2ab3bc66c..27820b761bb1c 100644 --- a/src/Tools/Source/RunTests/ProcessTestExecutor.cs +++ b/src/Tools/Source/RunTests/ProcessTestExecutor.cs @@ -34,7 +34,7 @@ public string GetCommandLineArguments(AssemblyInfo assemblyInfo) builder.Append($@"test"); builder.Append($@" ""{assemblyInfo.AssemblyPath}"""); var typeInfoList = assemblyInfo.PartitionInfo.TypeInfoList; - if (typeInfoList.Length > 0 || !string.IsNullOrWhiteSpace(Options.Trait) || !string.IsNullOrWhiteSpace(Options.NoTrait)) + if (typeInfoList.Length > 0 || !string.IsNullOrWhiteSpace(Options.TestFilter)) { builder.Append(" --filter "); var any = false; @@ -44,22 +44,10 @@ public string GetCommandLineArguments(AssemblyInfo assemblyInfo) builder.Append(typeInfo.FullName); } - if (Options.Trait is object) + if (Options.TestFilter is object) { - foreach (var trait in Options.Trait.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) - { - MaybeAddSeparator(); - builder.Append($"Trait={trait}"); - } - } - - if (Options.NoTrait is object) - { - foreach (var trait in Options.NoTrait.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) - { - MaybeAddSeparator('&'); - builder.Append($"Trait!~{trait}"); - } + MaybeAddSeparator(); + builder.Append(Options.TestFilter); } void MaybeAddSeparator(char separator = '|') diff --git a/src/Tools/Source/RunTests/Program.cs b/src/Tools/Source/RunTests/Program.cs index d3dba579a7b10..a6f16fbd6a100 100644 --- a/src/Tools/Source/RunTests/Program.cs +++ b/src/Tools/Source/RunTests/Program.cs @@ -35,7 +35,6 @@ internal static async Task Main(string[] args) { Logger.Log("RunTest command line"); Logger.Log(string.Join(" ", args)); - var options = Options.Parse(args); if (options == null) { @@ -364,8 +363,7 @@ private static ProcessTestExecutor CreateTestExecutor(Options options) dotnetFilePath: options.DotnetFilePath, procDumpInfo: options.CollectDumps ? GetProcDumpInfo(options) : null, testResultsDirectory: options.TestResultsDirectory, - trait: options.Trait, - noTrait: options.NoTrait, + testFilter: options.TestFilter, includeHtml: options.IncludeHtml, retry: options.Retry); return new ProcessTestExecutor(testExecutionOptions); diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToDefinition.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToDefinition.cs index 6220293523140..fbeb7dacf37e2 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToDefinition.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToDefinition.cs @@ -26,7 +26,7 @@ public CSharpGoToDefinition(VisualStudioInstanceFactory instanceFactory) { } - [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition)] + [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)] public void GoToClassDeclaration() { var project = new ProjectUtils.Project(ProjectName); @@ -44,12 +44,12 @@ public void GoToClassDeclaration() SomeClass sc; }"); VisualStudio.Editor.PlaceCaret("SomeClass"); - VisualStudio.Editor.GoToDefinition(); + VisualStudio.Editor.GoToDefinition("FileDef.cs"); VisualStudio.Editor.Verify.TextContains(@"class SomeClass$$", assertCaretPosition: true); Assert.False(VisualStudio.Shell.IsActiveTabProvisional()); } - [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition)] + [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)] public void GoToDefinitionOpensProvisionalTabIfDocumentNotAlreadyOpen() { var project = new ProjectUtils.Project(ProjectName); @@ -69,7 +69,7 @@ public void GoToDefinitionOpensProvisionalTabIfDocumentNotAlreadyOpen() SomeClass sc; }"); VisualStudio.Editor.PlaceCaret("SomeClass"); - VisualStudio.Editor.GoToDefinition(); + VisualStudio.Editor.GoToDefinition("FileDef.cs"); VisualStudio.Editor.Verify.TextContains(@"class SomeClass$$", assertCaretPosition: true); Assert.True(VisualStudio.Shell.IsActiveTabProvisional()); } @@ -82,7 +82,7 @@ public void GoToDefinitionWithMultipleResults() partial class PartialClass { int i = 0; }"); - VisualStudio.Editor.GoToDefinition(); + VisualStudio.Editor.GoToDefinition("Class1.cs"); const string programReferencesCaption = "'PartialClass' declarations"; var results = VisualStudio.FindReferencesWindow.GetContents(programReferencesCaption); diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToImplementation.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToImplementation.cs index 58314f64bcd9b..dfda9c909c42e 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToImplementation.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToImplementation.cs @@ -24,7 +24,7 @@ public CSharpGoToImplementation(VisualStudioInstanceFactory instanceFactory) { } - [WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)] + [WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)] public void SimpleGoToImplementation() { var project = new ProjectUtils.Project(ProjectName); @@ -41,12 +41,12 @@ public void SimpleGoToImplementation() { }"); VisualStudio.Editor.PlaceCaret("interface IGoo"); - VisualStudio.Editor.GoToImplementation(); + VisualStudio.Editor.GoToImplementation("FileImplementation.cs"); VisualStudio.Editor.Verify.TextContains(@"class Implementation$$", assertCaretPosition: true); Assert.False(VisualStudio.Shell.IsActiveTabProvisional()); } - [WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)] + [WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)] public void GoToImplementationOpensProvisionalTabIfDocumentNotOpen() { var project = new ProjectUtils.Project(ProjectName); @@ -65,13 +65,13 @@ public void GoToImplementationOpensProvisionalTabIfDocumentNotOpen() { }"); VisualStudio.Editor.PlaceCaret("interface IBar"); - VisualStudio.Editor.GoToImplementation(); + VisualStudio.Editor.GoToImplementation("FileImplementation.cs"); VisualStudio.Editor.Verify.TextContains(@"class Implementation$$", assertCaretPosition: true); Assert.True(VisualStudio.Shell.IsActiveTabProvisional()); } // TODO: Enable this once the GoToDefinition tests are merged - [WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)] + [WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)] public void GoToImplementationFromMetadataAsSource() { var project = new ProjectUtils.Project(ProjectName); @@ -88,8 +88,8 @@ public void SomeMethod() } }"); VisualStudio.Editor.PlaceCaret("IDisposable d", charsOffset: -1); - VisualStudio.Editor.GoToDefinition(); - VisualStudio.Editor.GoToImplementation(); + VisualStudio.Editor.GoToDefinition("IDisposable.cs"); + VisualStudio.Editor.GoToImplementation("FileImplementation.cs"); VisualStudio.Editor.Verify.TextContains(@"class Implementation$$ : IDisposable", assertCaretPosition: true); } } diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSourceGenerators.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSourceGenerators.cs index 581f56afa4911..09680b4ec14eb 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSourceGenerators.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSourceGenerators.cs @@ -49,7 +49,7 @@ public static void Main() }"); VisualStudio.Editor.PlaceCaret(HelloWorldGenerator.GeneratedEnglishClassName); - VisualStudio.Editor.GoToDefinition(); + VisualStudio.Editor.GoToDefinition($"{HelloWorldGenerator.GeneratedEnglishClassName}.cs"); Assert.Equal($"{HelloWorldGenerator.GeneratedEnglishClassName}.cs {ServicesVSResources.generated_suffix}", VisualStudio.Shell.GetActiveWindowCaption()); Assert.Equal(HelloWorldGenerator.GeneratedEnglishClassName, VisualStudio.Editor.GetSelectedText()); } diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/LanguageServerProtocol/LspGoToDefinition.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/LanguageServerProtocol/LspGoToDefinition.cs new file mode 100644 index 0000000000000..066974ff68766 --- /dev/null +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/LanguageServerProtocol/LspGoToDefinition.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.VisualStudio.IntegrationTest.Utilities; +using Microsoft.VisualStudio.IntegrationTest.Utilities.Common; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Abstractions; +using ProjectUtils = Microsoft.VisualStudio.IntegrationTest.Utilities.Common.ProjectUtils; + +namespace Roslyn.VisualStudio.IntegrationTests.LanguageServerProtocol +{ + [Collection(nameof(SharedIntegrationHostFixture))] + public class LspGoToDefinition : AbstractEditorTest + { + protected override string LanguageName => LanguageNames.CSharp; + + public LspGoToDefinition(VisualStudioInstanceFactory instanceFactory) + : base(instanceFactory, nameof(LspGoToDefinition)) + { + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)] + public void GoToDefinitionLSP() + { + var project = new ProjectUtils.Project(ProjectName); + VisualStudio.SolutionExplorer.AddFile(project, "FileDef.cs"); + VisualStudio.SolutionExplorer.OpenFile(project, "FileDef.cs"); + VisualStudio.Editor.SetText( +@"class SomeClass +{ +} +"); + VisualStudio.SolutionExplorer.CloseCodeFile(project, "FileDef.cs", saveFile: true); + VisualStudio.SolutionExplorer.AddFile(project, "FileConsumer.cs"); + VisualStudio.SolutionExplorer.OpenFile(project, "FileConsumer.cs"); + VisualStudio.Editor.SetText( +@"class SomeOtherClass +{ + SomeClass sc; +}"); + VisualStudio.Editor.PlaceCaret("SomeClass"); + VisualStudio.Editor.GoToDefinition("FileDef.cs"); + System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); + VisualStudio.Editor.Verify.TextContains(@"class SomeClass$$", assertCaretPosition: true); + Assert.True(VisualStudio.Shell.IsActiveTabProvisional()); + } + } +} diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicGoToDefinition.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicGoToDefinition.cs index 212426ef7bd34..c02688f95e41c 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicGoToDefinition.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicGoToDefinition.cs @@ -38,7 +38,7 @@ public void GoToClassDeclaration() Dim gibberish As SomeClass End Class"); VisualStudio.Editor.PlaceCaret("SomeClass"); - VisualStudio.Editor.GoToDefinition(); + VisualStudio.Editor.GoToDefinition("FileDef.vb"); VisualStudio.Editor.Verify.TextContains(@"Class SomeClass$$", assertCaretPosition: true); Assert.False(VisualStudio.Shell.IsActiveTabProvisional()); } @@ -52,13 +52,13 @@ Dim i As Integer$$ End Class"); VisualStudio.Workspace.SetFeatureOption(feature: "VisualStudioNavigationOptions", optionName: "NavigateToObjectBrowser", language: LanguageName, valueString: "True"); - VisualStudio.Editor.GoToDefinition(); + VisualStudio.Editor.GoToDefinition("Class1.vb"); Assert.Equal("Object Browser", VisualStudio.Shell.GetActiveWindowCaption()); VisualStudio.Workspace.SetFeatureOption(feature: "VisualStudioNavigationOptions", optionName: "NavigateToObjectBrowser", language: LanguageName, valueString: "False"); VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "Class1.vb"); - VisualStudio.Editor.GoToDefinition(); + VisualStudio.Editor.GoToDefinition("Int32.vb"); VisualStudio.Editor.Verify.TextContains("Public Structure Int32"); } } diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicGoToImplementation.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicGoToImplementation.cs index cb3cd998728f1..4bf561cb763d3 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicGoToImplementation.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicGoToImplementation.cs @@ -22,7 +22,7 @@ public BasicGoToImplementation(VisualStudioInstanceFactory instanceFactory) { } - [WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)] + [WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)] public void SimpleGoToImplementation() { var project = new ProjectUtils.Project(ProjectName); @@ -38,7 +38,7 @@ Implements IGoo @"Interface IGoo End Interface"); VisualStudio.Editor.PlaceCaret("Interface IGoo"); - VisualStudio.Editor.GoToImplementation(); + VisualStudio.Editor.GoToImplementation("FileImplementation.vb"); VisualStudio.Editor.Verify.TextContains(@"Class Implementation$$", assertCaretPosition: true); Assert.False(VisualStudio.Shell.IsActiveTabProvisional()); } diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/Editor_OutOfProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/Editor_OutOfProc.cs index 30fd0c355bc75..ab947f52b3719 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/Editor_OutOfProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/Editor_OutOfProc.cs @@ -362,11 +362,17 @@ private TextSpan[] Deserialize(string[] v) }).ToArray(); } - public void GoToDefinition() - => _editorInProc.GoToDefinition(); + public void GoToDefinition(string viewName) + { + _editorInProc.GoToDefinition(); + _editorInProc.WaitForActiveView(viewName); + } - public void GoToImplementation() - => _editorInProc.GoToImplementation(); + public void GoToImplementation(string viewName) + { + _editorInProc.GoToImplementation(); + _editorInProc.WaitForActiveView(viewName); + } public void SendExplicitFocus() => _editorInProc.SendExplicitFocus(); diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs index 89a7409a6f4cd..5f7f912e949bc 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs @@ -332,6 +332,9 @@ private static Process StartNewVisualStudioProcess(string installationPath, int // Disable background download UI to avoid toasts Process.Start(CreateSilentStartInfo(vsRegEditExeFile, $"set \"{installationPath}\" {Settings.Default.VsRootSuffix} HKCU \"FeatureFlags\\Setup\\BackgroundDownload\" Value dword 0")).WaitForExit(); + var lspRegistryValue = string.Equals(Environment.GetEnvironmentVariable("ROSLYN_LSPEDITOR"), "true", StringComparison.OrdinalIgnoreCase) ? "1" : "0"; + Process.Start(CreateSilentStartInfo(vsRegEditExeFile, $"set \"{installationPath}\" {Settings.Default.VsRootSuffix} HKCU \"FeatureFlags\\Roslyn\\LSP\\Editor\" Value dword {lspRegistryValue}")).WaitForExit(); + // Remove legacy experiment setting for controlling async completion to ensure it does not interfere. // We no longer set this value, but it could be in place from an earlier test run on the same machine. var disabledFlights = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\ABExp\LocalTest", "DisabledFlights", Array.Empty()) as string[] ?? Array.Empty();