diff --git a/src/PowerShellEditorServices/Server/PsesDebugServer.cs b/src/PowerShellEditorServices/Server/PsesDebugServer.cs index 9f48a0f2d..aca7aa963 100644 --- a/src/PowerShellEditorServices/Server/PsesDebugServer.cs +++ b/src/PowerShellEditorServices/Server/PsesDebugServer.cs @@ -5,7 +5,9 @@ using System.IO; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.PowerShell.EditorServices.Handlers; +using Microsoft.PowerShell.EditorServices.Logging; using Microsoft.PowerShell.EditorServices.Services; using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host; using OmniSharp.Extensions.DebugAdapter.Server; @@ -89,23 +91,40 @@ public async Task StartAsync() // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Initialize .OnInitialize(async (server, _, cancellationToken) => { - // Start the host if not already started, and enable debug mode (required - // for remote debugging). - // - // TODO: We might need to fill in HostStartOptions here. - _startedPses = !await _psesHost.TryStartAsync(new HostStartOptions(), cancellationToken).ConfigureAwait(false); - _psesHost.DebugContext.EnableDebugMode(); - - // We need to give the host a handle to the DAP so it can register - // notifications (specifically for sendKeyPress). - if (_isTemp) + try { - _psesHost.DebugServer = server; + // Start the host if not already started, and enable debug mode (required + // for remote debugging). + // + // TODO: We might need to fill in HostStartOptions here. + _startedPses = !await _psesHost.TryStartAsync(new HostStartOptions(), cancellationToken).ConfigureAwait(false); + _psesHost.DebugContext.EnableDebugMode(); + + // We need to give the host a handle to the DAP so it can register + // notifications (specifically for sendKeyPress). + if (_isTemp) + { + _psesHost.DebugServer = server; + } + + // Clear any existing breakpoints before proceeding. + BreakpointService breakpointService = server.GetService(); + await breakpointService.RemoveAllBreakpointsAsync().ConfigureAwait(false); + } + catch (Exception e) + { + // Never let an exception escape this delegate. OmniSharp's + // DebugAdapterServer only signals its internal initialize-complete + // subject on the success path of the InitializeRequest handler, so a + // throw here leaves DebugAdapterServer.From() (and thus StartAsync) + // awaiting that subject forever -- wedging startup and riding the job + // timeout instead of failing fast. Log the failure and signal shutdown + // so WaitForShutdown unblocks and the process can exit cleanly. + ServiceProvider.GetService()? + .CreateLogger() + .LogException("Failed to start the debug server; terminating the debug session.", e); + _serverStopped.TrySetResult(true); } - - // Clear any existing breakpoints before proceeding. - BreakpointService breakpointService = server.GetService(); - await breakpointService.RemoveAllBreakpointsAsync().ConfigureAwait(false); }) // The OnInitialized delegate gets run right before the server responds to the _Initialize_ request: // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Initialize @@ -134,7 +153,7 @@ public void Dispose() _debugAdapterServer?.Dispose(); _inputStream.Dispose(); _outputStream.Dispose(); - _serverStopped.SetResult(true); + _serverStopped.TrySetResult(true); // TODO: If the debugger has stopped, should we clear the breakpoints? } diff --git a/src/PowerShellEditorServices/Services/PowerShell/Utility/PowerShellExtensions.cs b/src/PowerShellEditorServices/Services/PowerShell/Utility/PowerShellExtensions.cs index f24ae98bc..a0f10b8b1 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Utility/PowerShellExtensions.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Utility/PowerShellExtensions.cs @@ -138,10 +138,31 @@ public static void SetCorrectExecutionPolicy(this PowerShell pwsh, ILogger logge { // We want to get the list hierarchy of execution policies // Calling the cmdlet is the simplest way to do that - IReadOnlyList policies = pwsh - .AddCommand(@"Microsoft.PowerShell.Security\Get-ExecutionPolicy") - .AddParameter("List") - .InvokeAndClear(); + IReadOnlyList policies; + try + { + policies = pwsh + .AddCommand(@"Microsoft.PowerShell.Security\Get-ExecutionPolicy") + .AddParameter("List") + .InvokeAndClear(); + } + catch (Exception e) + { + // Some Windows PowerShell servicing builds throw a type-data conflict + // ("The member ... is already present" on ObjectSecurity) when + // autoloading Microsoft.PowerShell.Security into a runspace whose + // InitialSessionState already carries that module's type data. + // Configuring the execution policy is best-effort, so log and skip + // rather than letting it abort host startup (which manifests as a hang). + logger.LogError(e, "Failed to query the execution policy; skipping execution policy configuration."); + return; + } + + // We need at least the CurrentUser and LocalMachine scopes to proceed. + if (policies is null || policies.Count < 2) + { + return; + } // The policies come out in the following order: // - MachinePolicy diff --git a/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs index 27e153751..4dcd4afe9 100644 --- a/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs +++ b/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs @@ -24,14 +24,6 @@ namespace PowerShellEditorServices.Test.E2E { - /// - /// Every test in this class is skipped at discovery time on in-box Windows - /// PowerShell (via and - /// ) because the shared - /// debug-adapter startup can wedge there since the - /// 20260614 runner image, riding the job timeout. See - /// https://github.com/PowerShell/PowerShellEditorServices/issues/2323. - /// [Trait("Category", "DAP")] // ITestOutputHelper is injected by XUnit // https://xunit.net/docs/capturing-output @@ -264,7 +256,7 @@ private async Task ReadScriptLogLineAsync() } } - [SkippableFactOnWindowsPowerShell] + [Fact] public void CanInitializeWithCorrectServerSettings() { Assert.True(client.ServerSettings.SupportsConditionalBreakpoints); @@ -276,7 +268,7 @@ public void CanInitializeWithCorrectServerSettings() Assert.True(client.ServerSettings.SupportsDelayedStackTraceLoading); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task UsesDotSourceOperatorAndQuotesAsync() { string filePath = NewTestFile(GenerateLoggingScript("$($MyInvocation.Line)")); @@ -288,7 +280,7 @@ public async Task UsesDotSourceOperatorAndQuotesAsync() Assert.StartsWith(". '", actual); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task UsesCallOperatorWithSettingAsync() { string filePath = NewTestFile(GenerateLoggingScript("$($MyInvocation.Line)")); @@ -300,7 +292,7 @@ public async Task UsesCallOperatorWithSettingAsync() Assert.StartsWith("& '", actual); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanLaunchScriptWithNoBreakpointsAsync() { string filePath = NewTestFile(GenerateLoggingScript("works")); @@ -314,7 +306,7 @@ public async Task CanLaunchScriptWithNoBreakpointsAsync() Assert.Equal("works", actual); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanSetBreakpointsAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode, @@ -365,7 +357,7 @@ public async Task CanSetBreakpointsAsync() Assert.Equal("after breakpoint", afterBreakpointActual); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task FailsIfStacktraceRequestedWhenNotPaused() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode, @@ -396,7 +388,7 @@ await Assert.ThrowsAsync(() => client.RequestStackTrace( )); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task SendsInitialLabelBreakpointForPerformanceReasons() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode, @@ -454,7 +446,7 @@ public async Task SendsInitialLabelBreakpointForPerformanceReasons() // PowerShell, we avoid all issues with our test project (and the xUnit executable) not // having System.Windows.Forms deployed, and can instead rely on the Windows Global Assembly // Cache (GAC) to find it. - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanStepPastSystemWindowsForms() { Skip.IfNot(PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, @@ -497,7 +489,7 @@ public async Task CanStepPastSystemWindowsForms() // commented. Since in some cases (such as Windows PowerShell, or the script not having a // backing ScriptFile) we just wrap the script with braces, we had a bug where the last // brace would be after the comment. We had to ensure we wrapped with newlines instead. - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanLaunchScriptWithCommentedLastLineAsync() { string script = GenerateLoggingScript("$($MyInvocation.Line)", "$(1+1)") + "# a comment at the end"; @@ -521,7 +513,7 @@ public async Task CanLaunchScriptWithCommentedLastLineAsync() Assert.Equal("2", await ReadScriptLogLineAsync()); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanRunPesterTestFile() { Skip.If(true, "Pester test is broken."); @@ -566,7 +558,7 @@ public async Task CanRunPesterTestFile() [InlineData("-ProcessId 1234 -RunspaceId 5678", null, null, 1234, 5678, null)] [InlineData("-ProcessId 1234 -RunspaceId 5678 -ComputerName comp", "comp", null, 1234, 5678, null)] [InlineData("-CustomPipeName testpipe -RunspaceName rs-name", null, "testpipe", 0, 0, "rs-name")] - [SkippableTheoryOnWindowsPowerShell] + [SkippableTheory] public async Task CanLaunchScriptWithNewChildAttachSession( string paramString, string? expectedComputerName, @@ -578,6 +570,9 @@ public async Task CanLaunchScriptWithNewChildAttachSession( Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode, "PowerShellEditorServices.Command is not signed to run FLM in Constrained Language Mode."); + Skip.If(PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, + "The Start-DebugAttachSession reverse-request round-trip is flaky on in-box Windows PowerShell CI runners (see #2323)."); + string script = NewTestFile($"Start-DebugAttachSession {paramString}"); using CancellationTokenSource timeoutCts = new(30000); @@ -604,7 +599,7 @@ public async Task CanLaunchScriptWithNewChildAttachSession( await terminatedTcs.Task; } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanLaunchScriptWithNewChildAttachSessionAsJob() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode, @@ -638,14 +633,15 @@ public async Task CanLaunchScriptWithNewChildAttachSessionAsJob() await terminatedTcs.Task; } - // Timeout is a per-test backstop; the Windows PowerShell skip happens at - // discovery time via the attribute (see the class remarks). - [SkippableFactOnWindowsPowerShell(Timeout = 15000)] + [SkippableFact(Timeout = 15000)] public async Task CanAttachScriptWithPathMappings() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode, "Breakpoints can't be set in Constrained Language Mode."); + Skip.If(PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, + "In-box Windows PowerShell wedges on the cross-process Debug-Runspace attach handshake (see #2323)."); + string[] logStatements = ["$PSCommandPath", "after breakpoint"]; await RunWithAttachableProcess(logStatements, async (filePath, processId, runspaceId) => diff --git a/test/PowerShellEditorServices.Test.E2E/Hosts/SkippableFactOnWindowsPowerShellAttribute.cs b/test/PowerShellEditorServices.Test.E2E/Hosts/SkippableFactOnWindowsPowerShellAttribute.cs deleted file mode 100644 index 5abb62a09..000000000 --- a/test/PowerShellEditorServices.Test.E2E/Hosts/SkippableFactOnWindowsPowerShellAttribute.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Xunit; -using Xunit.Sdk; - -namespace PowerShellEditorServices.Test.E2E; - -/// -/// The shared skip reason used by the discovery-time Windows PowerShell skip -/// attributes for the end-to-end tests. -/// -/// -/// This is a runner-image regression, not a PSES code change: re-running a -/// commit that predates all recent PRs (and previously passed) reproduces the -/// same hang on the current windows-latest image, while macOS and Linux stay -/// green. The wedge is in the in-box Windows PowerShell server's startup, so it -/// affects both the debug adapter and language server end-to-end suites. -/// -internal static class WindowsPowerShellServerStartupSkip -{ - public const string Reason = "The in-box Windows PowerShell server can wedge during startup on the current windows-latest runner image (a runner-image regression, not our code); see https://github.com/PowerShell/PowerShellEditorServices/issues/2323."; -} - -/// -/// A that additionally skips the test at -/// discovery time when running under in-box Windows PowerShell. -/// -/// -/// A runtime in the test body cannot prevent -/// the per-test IAsyncLifetime.InitializeAsync from running first, because -/// xUnit invokes the lifetime setup (which starts the PSES server) before the -/// method body. When the hang occurs during that setup, a body-level skip is never -/// reached. Setting here makes xUnit treat the -/// test as statically skipped, so it never instantiates the test class or runs -/// InitializeAsync. The discoverer is -/// retained so runtime calls (e.g. for Constrained Language -/// Mode) still work when the test is not skipped at discovery time. -/// -/// Caveat: xUnit still creates an even when -/// every test method in the class is skipped at discovery time, so a fixture that -/// starts the server in its own InitializeAsync (e.g. LSPTestsFixture) -/// must additionally guard against starting it under Windows PowerShell. -/// -/// -[XunitTestCaseDiscoverer("Xunit.Sdk.SkippableFactDiscoverer", "Xunit.SkippableFact")] -public sealed class SkippableFactOnWindowsPowerShellAttribute : SkippableFactAttribute -{ - public SkippableFactOnWindowsPowerShellAttribute() - { - if (PsesStdioLanguageServerProcessHost.IsWindowsPowerShell) - { - Skip = WindowsPowerShellServerStartupSkip.Reason; - } - } -} diff --git a/test/PowerShellEditorServices.Test.E2E/Hosts/SkippableTheoryOnWindowsPowerShellAttribute.cs b/test/PowerShellEditorServices.Test.E2E/Hosts/SkippableTheoryOnWindowsPowerShellAttribute.cs deleted file mode 100644 index 3f7ee8621..000000000 --- a/test/PowerShellEditorServices.Test.E2E/Hosts/SkippableTheoryOnWindowsPowerShellAttribute.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Xunit; -using Xunit.Sdk; - -namespace PowerShellEditorServices.Test.E2E; - -/// -/// A that additionally skips the theory at -/// discovery time when running under in-box Windows PowerShell. See -/// for why the skip must -/// happen at discovery time rather than via an in-body call. -/// -[XunitTestCaseDiscoverer("Xunit.Sdk.SkippableTheoryDiscoverer", "Xunit.SkippableFact")] -public sealed class SkippableTheoryOnWindowsPowerShellAttribute : SkippableTheoryAttribute -{ - public SkippableTheoryOnWindowsPowerShellAttribute() - { - if (PsesStdioLanguageServerProcessHost.IsWindowsPowerShell) - { - Skip = WindowsPowerShellServerStartupSkip.Reason; - } - } -} diff --git a/test/PowerShellEditorServices.Test.E2E/LSPTestsFixtures.cs b/test/PowerShellEditorServices.Test.E2E/LSPTestsFixtures.cs index 6db41ae37..ecda59880 100644 --- a/test/PowerShellEditorServices.Test.E2E/LSPTestsFixtures.cs +++ b/test/PowerShellEditorServices.Test.E2E/LSPTestsFixtures.cs @@ -42,18 +42,6 @@ public class LSPTestsFixture : IAsyncLifetime public async Task InitializeAsync() { - // All LSP end-to-end tests are skipped at discovery time on Windows - // PowerShell (see SkippableFactOnWindowsPowerShell), but xUnit still - // creates this class fixture even when every test method is skipped. - // The in-box Windows PowerShell server can wedge during startup on the - // current windows-latest runner image (a runner-image regression, not - // our code); see https://github.com/PowerShell/PowerShellEditorServices/issues/2323. - // So we must not start the server here on Windows PowerShell. - if (PsesStdioLanguageServerProcessHost.IsWindowsPowerShell) - { - return; - } - (StreamReader stdout, StreamWriter stdin) = await _psesHost.Start(); // Splice the streams together and enable debug logging of all messages sent and received @@ -112,8 +100,11 @@ public async Task InitializeAsync() public async Task DisposeAsync() { - // The server is never started on Windows PowerShell (see - // InitializeAsync), so there is nothing to shut down there. + // If InitializeAsync failed before the client connected (e.g. the + // server never finished starting), PsesLanguageClient was never + // assigned, so there is nothing to shut down. Guarding here keeps a + // startup failure from being masked by a NullReferenceException + // during teardown. if (PsesLanguageClient is null) { return; diff --git a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs index f9e9439e9..c9ed3dc1c 100644 --- a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs +++ b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs @@ -25,15 +25,6 @@ namespace PowerShellEditorServices.Test.E2E { - /// - /// Every test in this class is skipped at discovery time on in-box Windows - /// PowerShell (via ) - /// because the shared startup spawns an in-box - /// Windows PowerShell server that can wedge there since the 20260614 runner - /// image, riding the job timeout. This is the same server-startup hang that - /// affects the debug adapter tests; it is not specific to either protocol. - /// See https://github.com/PowerShell/PowerShellEditorServices/issues/2323. - /// [Trait("Category", "LSP")] public class LanguageServerProtocolMessageTests : IClassFixture, IDisposable { @@ -101,7 +92,7 @@ private async Task WaitForDiagnosticsAsync() } } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendPowerShellGetVersionRequestAsync() { PowerShellVersion details @@ -121,7 +112,7 @@ PowerShellVersion details } } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendWorkspaceSymbolRequestAsync() { NewTestFile(@" @@ -143,7 +134,7 @@ function CanSendWorkspaceSymbolRequest { Assert.Equal("function CanSendWorkspaceSymbolRequest ()", symbol.Name); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanReceiveDiagnosticsFromFileOpenAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode && PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, @@ -156,7 +147,7 @@ public async Task CanReceiveDiagnosticsFromFileOpenAsync() Assert.Equal("PSUseDeclaredVarsMoreThanAssignments", diagnostic.Code); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task WontReceiveDiagnosticsFromFileOpenThatIsNotPowerShellAsync() { NewTestFile("$a = 4", languageId: "plaintext"); @@ -165,7 +156,7 @@ public async Task WontReceiveDiagnosticsFromFileOpenThatIsNotPowerShellAsync() Assert.Empty(Diagnostics); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanReceiveDiagnosticsFromFileChangedAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode && PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, @@ -216,7 +207,7 @@ public async Task CanReceiveDiagnosticsFromFileChangedAsync() Assert.Equal("PSUseDeclaredVarsMoreThanAssignments", diagnostic.Code); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanReceiveDiagnosticsFromConfigurationChangeAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode && PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, @@ -275,7 +266,7 @@ public async Task CanReceiveDiagnosticsFromConfigurationChangeAsync() Assert.Equal("PSUseDeclaredVarsMoreThanAssignments", diagnostic.Code); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendFoldingRangeRequestAsync() { string scriptPath = NewTestFile(@"gci | % { @@ -316,7 +307,7 @@ await PsesLanguageClient }); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanSendFormattingRequestAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode && PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, @@ -352,7 +343,7 @@ public async Task CanSendFormattingRequestAsync() Assert.Contains("\t", textEdit.NewText); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanSendRangeFormattingRequestAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode && PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, @@ -401,7 +392,7 @@ public async Task CanSendRangeFormattingRequestAsync() Assert.Contains("\t", textEdit.NewText); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendDocumentSymbolRequestAsync() { string scriptPath = NewTestFile(@" @@ -447,7 +438,7 @@ await PsesLanguageClient }); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendReferencesRequestAsync() { string scriptPath = NewTestFile(@" @@ -490,7 +481,7 @@ function CanSendReferencesRequest { }); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendDocumentHighlightRequestAsync() { string scriptPath = NewTestFile(@" @@ -536,7 +527,7 @@ await PsesLanguageClient }); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendPowerShellGetPSHostProcessesRequestAsync() { Process process = new(); @@ -577,7 +568,7 @@ await PsesLanguageClient Assert.NotEmpty(pSHostProcessResponses); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendPowerShellGetRunspaceRequestAsync() { Process process = new(); @@ -620,7 +611,7 @@ await PsesLanguageClient Assert.NotEmpty(runspaceResponses); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendPesterLegacyCodeLensRequestAsync() { // Make sure LegacyCodeLens is enabled because we'll need it in this test. @@ -686,7 +677,7 @@ public async Task CanSendPesterLegacyCodeLensRequestAsync() }); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendPesterCodeLensRequestAsync() { // Make sure Pester legacy CodeLens is disabled because we'll need it in this test. @@ -796,7 +787,7 @@ public async Task CanSendPesterCodeLensRequestAsync() }); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task NoMessageIfPesterCodeLensDisabled() { // Make sure Pester legacy CodeLens is disabled because we'll need it in this test. @@ -839,7 +830,7 @@ public async Task NoMessageIfPesterCodeLensDisabled() Assert.Empty(codeLenses); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendFunctionReferencesCodeLensRequestAsync() { string filePath = NewTestFile(@" @@ -877,7 +868,7 @@ function CanSendReferencesCodeLensRequest { Assert.Equal("1 reference", codeLensResolveResult.Command.Title); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendClassReferencesCodeLensRequestAsync() { string filePath = NewTestFile(@" @@ -936,7 +927,7 @@ class ChildClass : MyBaseClass, System.IDisposable { Assert.Equal("4 references", codeLensResolveResult.Command.Title); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendEnumReferencesCodeLensRequestAsync() { string filePath = NewTestFile(@" @@ -981,7 +972,7 @@ enum MyEnum { Assert.Equal("3 references", codeLensResolveResult.Command.Title); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanSendCodeActionRequestAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode && PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, @@ -1037,7 +1028,7 @@ await PsesLanguageClient }); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendCompletionAndCompletionResolveRequestAsync() { CompletionList completionItems = await PsesLanguageClient.TextDocument.RequestCompletion( @@ -1060,9 +1051,12 @@ public async Task CanSendCompletionAndCompletionResolveRequestAsync() Assert.Contains(testDescription, updatedCompletionItem.Documentation.String); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanSendCompletionResolveWithModulePrefixRequestAsync() { + Skip.If(PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, + "Module-prefixed command completion returns no items on the Windows PowerShell server (see #1355)."); + await PsesLanguageClient .SendRequest( "evaluate", @@ -1107,7 +1101,7 @@ await PsesLanguageClient } } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendHoverRequestAsync() { string filePath = NewTestFile(testCommand); @@ -1132,7 +1126,7 @@ public async Task CanSendHoverRequestAsync() }); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendSignatureHelpRequestAsync() { string filePath = NewTestFile($"{testCommand} -"); @@ -1156,7 +1150,7 @@ public async Task CanSendSignatureHelpRequestAsync() Assert.Contains(testCommand, signatureHelp.Signatures.First().Label); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendDefinitionRequestAsync() { string scriptPath = NewTestFile(@" @@ -1187,7 +1181,7 @@ await PsesLanguageClient Assert.Equal(33, locationOrLocationLink.Location.Range.End.Character); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanSendGetCommentHelpRequestAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode && PsesStdioLanguageServerProcessHost.IsWindowsPowerShell, @@ -1226,7 +1220,7 @@ await PsesLanguageClient Assert.Contains("myParam", commentHelpRequestResult.Content[7]); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendEvaluateRequestAsync() { EvaluateResponseBody evaluateResponseBody = @@ -1245,7 +1239,7 @@ await PsesLanguageClient } // getCommand gets all the commands in the system, and is not optimized and can take forever on CI systems - [SkippableFactOnWindowsPowerShell(Timeout = 120000)] + [SkippableFact(Timeout = 120000)] public async Task CanSendGetCommandRequestAsync() { Skip.If( @@ -1264,7 +1258,7 @@ await PsesLanguageClient Assert.True(pSCommandMessages.Count > 20); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanSendExpandAliasRequestAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode, @@ -1283,7 +1277,7 @@ await PsesLanguageClient Assert.Equal("Get-ChildItem", expandAliasResult.Text); } - [SkippableFactOnWindowsPowerShell] + [SkippableFact] public async Task CanSendExpandAliasRequestWithMultipleAliasesAsync() { Skip.If(PsesStdioLanguageServerProcessHost.RunningInConstrainedLanguageMode, @@ -1306,7 +1300,7 @@ await PsesLanguageClient Assert.Equal("Get-ChildItem | Where-Object Name | ForEach-Object Name", expandAliasResult.Text); } - [SkippableFactOnWindowsPowerShell] + [Fact] public async Task CanSendSemanticTokenRequestAsync() { const string scriptContent = "function";