From 7b788d9b033c449bea269a28a3f9956dac46c330 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 2 Feb 2022 13:42:22 -0800 Subject: [PATCH 001/613] Update CHANGELOG for `v3.1.2` --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db69f43e0..d4acbd47a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # PowerShell Editor Services Release History +## v3.1.2 +### Wednesday, February 02, 2022 + +- 🐛 📟 [vscode-powershell #3786](https://github.com/PowerShell/PowerShellEditorServices/pull/1691) - Print prompt and command when `WriteInputToHost` is true. +- 🐛 📟 [vscode-powershell #3685](https://github.com/PowerShell/PowerShellEditorServices/pull/1690) - Display prompt after `F8` finishes. +- 🐛 🔍 [vscode-powershell #3522](https://github.com/PowerShell/PowerShellEditorServices/pull/1685) - Synchronize PowerShell debugger and DAP server state. +- ✨ 🔍 [PowerShellEditorServices #1680](https://github.com/PowerShell/PowerShellEditorServices/pull/1680) - Display `DictionaryEntry` as key/value pairs in debugger. (Thanks @JustinGrote!) + ## v3.1.1 ### Monday, January 24, 2022 From af984e8801c10894a101436ca765ddc02ed7dc36 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 2 Feb 2022 13:42:22 -0800 Subject: [PATCH 002/613] Bump version to `v3.1.2` --- PowerShellEditorServices.Common.props | 2 +- module/PowerShellEditorServices/PowerShellEditorServices.psd1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PowerShellEditorServices.Common.props b/PowerShellEditorServices.Common.props index e0ea97281..dbb7d3794 100644 --- a/PowerShellEditorServices.Common.props +++ b/PowerShellEditorServices.Common.props @@ -1,6 +1,6 @@ - 3.1.1 + 3.1.2 Microsoft © Microsoft Corporation. diff --git a/module/PowerShellEditorServices/PowerShellEditorServices.psd1 b/module/PowerShellEditorServices/PowerShellEditorServices.psd1 index c0686bbc8..f3478b2a8 100644 --- a/module/PowerShellEditorServices/PowerShellEditorServices.psd1 +++ b/module/PowerShellEditorServices/PowerShellEditorServices.psd1 @@ -19,7 +19,7 @@ RootModule = if ($PSEdition -eq 'Core') } # Version number of this module. -ModuleVersion = '3.1.1' +ModuleVersion = '3.1.2' # ID used to uniquely identify this module GUID = '9ca15887-53a2-479a-9cda-48d26bcb6c47' From e4bc6934630b216021a2594197b34ef3b145732b Mon Sep 17 00:00:00 2001 From: Andy Schwartzmeyer Date: Thu, 3 Feb 2022 12:34:32 -0800 Subject: [PATCH 003/613] Remove temporary `dotnet publish` workaround (#1698) --- .../PowerShellEditorServices.Hosting.csproj | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj index 58d4fa85c..7e9c826f3 100644 --- a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj +++ b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj @@ -6,18 +6,6 @@ Microsoft.PowerShell.EditorServices.Hosting - - - - <_ResolvedCopyLocalPublishAssets - Include="@(_NETStandardLibraryNETFrameworkLib)" - Condition="'%(_NETStandardLibraryNETFrameworkLib.FileName)' != 'netfx.force.conflicts'" - /> - - - $(DefineConstants);CoreCLR From 5f54c43d4bc9c03df143056cf76163ada6294a2d Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 8 Feb 2022 13:36:16 -0600 Subject: [PATCH 004/613] Add `Thread.Sleep(100)` to throttle REPL when it's non-interactive (#1694) Co-authored-by: Colin Blaise --- .../Services/PowerShell/Host/PsesInternalHost.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs index dc1f1bc41..d7c34faee 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs @@ -600,6 +600,8 @@ private void DoOneRepl(CancellationToken cancellationToken) { if (!_hostInfo.ConsoleReplEnabled) { + // Throttle the REPL loop with a sleep because we're not interactively reading input from the user. + Thread.Sleep(100); return; } From 77d1ffcac2a5db92a6af89e50972f372ec3a87a2 Mon Sep 17 00:00:00 2001 From: Andy Schwartzmeyer Date: Tue, 8 Feb 2022 16:57:15 -0800 Subject: [PATCH 005/613] Replace superfluous `Default` member with default values (#1693) I think this was a case of premature optimization. We're using C# records, which should be as cheap as an object as they come, especially when we can rely on the compiler for default values. Now we're passing fewer objects around too. --- .../Services/Extension/ExtensionService.cs | 2 +- .../PowerShell/Console/LegacyReadLine.cs | 8 ++--- .../Debugging/DscBreakpointCapability.cs | 2 +- .../PowerShell/Execution/ExecutionOptions.cs | 27 ++------------- .../Execution/SynchronousDelegateTask.cs | 8 ++--- .../Execution/SynchronousPowerShellTask.cs | 2 +- .../PowerShell/Host/PsesInternalHost.cs | 33 +++++++++++-------- .../PowerShell/Utility/CommandHelpers.cs | 2 +- .../Workspace/RemoteFileManagerService.cs | 4 +-- 9 files changed, 35 insertions(+), 53 deletions(-) diff --git a/src/PowerShellEditorServices/Services/Extension/ExtensionService.cs b/src/PowerShellEditorServices/Services/Extension/ExtensionService.cs index cb4562c43..116273734 100644 --- a/src/PowerShellEditorServices/Services/Extension/ExtensionService.cs +++ b/src/PowerShellEditorServices/Services/Extension/ExtensionService.cs @@ -107,7 +107,7 @@ internal Task InitializeAsync() // Register the editor object in the runspace return ExecutionService.ExecuteDelegateAsync( $"Create ${PSEditorVariableName} object", - ExecutionOptions.Default, + executionOptions: null, (pwsh, _) => pwsh.Runspace.SessionStateProxy.PSVariable.Set(psEditor), CancellationToken.None); } diff --git a/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs b/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs index a29fe17f2..c83383e3d 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs @@ -84,14 +84,14 @@ public override string ReadLine(CancellationToken cancellationToken) .AddParameter("CursorColumn", currentCursorIndex) .AddParameter("Options", null); - currentCompletion = _psesHost.InvokePSCommand(command, PowerShellExecutionOptions.Default, cancellationToken).FirstOrDefault(); + currentCompletion = _psesHost.InvokePSCommand(command, executionOptions: null, cancellationToken).FirstOrDefault(); } else { currentCompletion = _psesHost.InvokePSDelegate( "Legacy readline inline command completion", - ExecutionOptions.Default, - (pwsh, cancellationToken) => CommandCompletion.CompleteInput(inputAfterCompletion, currentCursorIndex, options: null, pwsh), + executionOptions: null, + (pwsh, _) => CommandCompletion.CompleteInput(inputAfterCompletion, currentCursorIndex, options: null, pwsh), cancellationToken); if (currentCompletion.CompletionMatches.Count > 0) @@ -198,7 +198,7 @@ public override string ReadLine(CancellationToken cancellationToken) PSCommand command = new PSCommand() .AddCommand("Get-History"); - currentHistory = _psesHost.InvokePSCommand(command, PowerShellExecutionOptions.Default, cancellationToken); + currentHistory = _psesHost.InvokePSCommand(command, executionOptions: null, cancellationToken); if (currentHistory != null) { diff --git a/src/PowerShellEditorServices/Services/PowerShell/Debugging/DscBreakpointCapability.cs b/src/PowerShellEditorServices/Services/PowerShell/Debugging/DscBreakpointCapability.cs index 0ad294bd0..c13d3e301 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Debugging/DscBreakpointCapability.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Debugging/DscBreakpointCapability.cs @@ -164,7 +164,7 @@ public static Task GetDscCapabilityAsync( return psesHost.ExecuteDelegateAsync( nameof(getDscBreakpointCapabilityFunc), - ExecutionOptions.Default, + executionOptions: null, getDscBreakpointCapabilityFunc, cancellationToken); } diff --git a/src/PowerShellEditorServices/Services/PowerShell/Execution/ExecutionOptions.cs b/src/PowerShellEditorServices/Services/PowerShell/Execution/ExecutionOptions.cs index 4965e3415..af5d9e7e9 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Execution/ExecutionOptions.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Execution/ExecutionOptions.cs @@ -15,39 +15,16 @@ public enum ExecutionPriority // Generally the executor will do the right thing though; some options just priority over others. public record ExecutionOptions { - public static ExecutionOptions Default = new() - { - Priority = ExecutionPriority.Normal, - MustRunInForeground = false, - InterruptCurrentForeground = false, - }; - - public ExecutionPriority Priority { get; init; } - + public ExecutionPriority Priority { get; init; } = ExecutionPriority.Normal; public bool MustRunInForeground { get; init; } - public bool InterruptCurrentForeground { get; init; } } public record PowerShellExecutionOptions : ExecutionOptions { - public static new PowerShellExecutionOptions Default = new() - { - Priority = ExecutionPriority.Normal, - MustRunInForeground = false, - InterruptCurrentForeground = false, - WriteOutputToHost = false, - WriteInputToHost = false, - ThrowOnError = true, - AddToHistory = false, - }; - public bool WriteOutputToHost { get; init; } - public bool WriteInputToHost { get; init; } - - public bool ThrowOnError { get; init; } - + public bool ThrowOnError { get; init; } = true; public bool AddToHistory { get; init; } } } diff --git a/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousDelegateTask.cs b/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousDelegateTask.cs index 343f930eb..2bec67fe9 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousDelegateTask.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousDelegateTask.cs @@ -23,7 +23,7 @@ public SynchronousDelegateTask( CancellationToken cancellationToken) : base(logger, cancellationToken) { - ExecutionOptions = executionOptions; + ExecutionOptions = executionOptions ?? new ExecutionOptions(); _representation = representation; _action = action; } @@ -58,7 +58,7 @@ public SynchronousDelegateTask( { _func = func; _representation = representation; - ExecutionOptions = executionOptions; + ExecutionOptions = executionOptions ?? new ExecutionOptions(); } public override ExecutionOptions ExecutionOptions { get; } @@ -94,7 +94,7 @@ public SynchronousPSDelegateTask( _psesHost = psesHost; _action = action; _representation = representation; - ExecutionOptions = executionOptions; + ExecutionOptions = executionOptions ?? new ExecutionOptions(); } public override ExecutionOptions ExecutionOptions { get; } @@ -131,7 +131,7 @@ public SynchronousPSDelegateTask( _psesHost = psesHost; _func = func; _representation = representation; - ExecutionOptions = executionOptions; + ExecutionOptions = executionOptions ?? new ExecutionOptions(); } public override ExecutionOptions ExecutionOptions { get; } diff --git a/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousPowerShellTask.cs b/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousPowerShellTask.cs index b438e84cc..c3a1132ad 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousPowerShellTask.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Execution/SynchronousPowerShellTask.cs @@ -36,7 +36,7 @@ public SynchronousPowerShellTask( _logger = logger; _psesHost = psesHost; _psCommand = command; - PowerShellExecutionOptions = executionOptions; + PowerShellExecutionOptions = executionOptions ?? new PowerShellExecutionOptions(); } public PowerShellExecutionOptions PowerShellExecutionOptions { get; } diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs index d7c34faee..5e790037d 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs @@ -307,7 +307,8 @@ public Task ExecuteDelegateAsync( Func func, CancellationToken cancellationToken) { - return InvokeTaskOnPipelineThreadAsync(new SynchronousPSDelegateTask(_logger, this, representation, executionOptions ?? ExecutionOptions.Default, func, cancellationToken)); + return InvokeTaskOnPipelineThreadAsync( + new SynchronousPSDelegateTask(_logger, this, representation, executionOptions, func, cancellationToken)); } public Task ExecuteDelegateAsync( @@ -316,7 +317,8 @@ public Task ExecuteDelegateAsync( Action action, CancellationToken cancellationToken) { - return InvokeTaskOnPipelineThreadAsync(new SynchronousPSDelegateTask(_logger, this, representation, executionOptions ?? ExecutionOptions.Default, action, cancellationToken)); + return InvokeTaskOnPipelineThreadAsync( + new SynchronousPSDelegateTask(_logger, this, representation, executionOptions, action, cancellationToken)); } public Task ExecuteDelegateAsync( @@ -325,7 +327,8 @@ public Task ExecuteDelegateAsync( Func func, CancellationToken cancellationToken) { - return InvokeTaskOnPipelineThreadAsync(new SynchronousDelegateTask(_logger, representation, executionOptions ?? ExecutionOptions.Default, func, cancellationToken)); + return InvokeTaskOnPipelineThreadAsync( + new SynchronousDelegateTask(_logger, representation, executionOptions, func, cancellationToken)); } public Task ExecuteDelegateAsync( @@ -334,7 +337,8 @@ public Task ExecuteDelegateAsync( Action action, CancellationToken cancellationToken) { - return InvokeTaskOnPipelineThreadAsync(new SynchronousDelegateTask(_logger, representation, executionOptions ?? ExecutionOptions.Default, action, cancellationToken)); + return InvokeTaskOnPipelineThreadAsync( + new SynchronousDelegateTask(_logger, representation, executionOptions, action, cancellationToken)); } public Task> ExecutePSCommandAsync( @@ -342,18 +346,17 @@ public Task> ExecutePSCommandAsync( CancellationToken cancellationToken, PowerShellExecutionOptions executionOptions = null) { - return InvokeTaskOnPipelineThreadAsync(new SynchronousPowerShellTask( - _logger, - this, - psCommand, - executionOptions ?? PowerShellExecutionOptions.Default, - cancellationToken)); + return InvokeTaskOnPipelineThreadAsync( + new SynchronousPowerShellTask(_logger, this, psCommand, executionOptions, cancellationToken)); } public Task ExecutePSCommandAsync( PSCommand psCommand, CancellationToken cancellationToken, - PowerShellExecutionOptions executionOptions = null) => ExecutePSCommandAsync(psCommand, cancellationToken, executionOptions); + PowerShellExecutionOptions executionOptions = null) + { + return ExecutePSCommandAsync(psCommand, cancellationToken, executionOptions); + } public TResult InvokeDelegate(string representation, ExecutionOptions executionOptions, Func func, CancellationToken cancellationToken) { @@ -374,7 +377,9 @@ public IReadOnlyList InvokePSCommand(PSCommand psCommand, Powe } public void InvokePSCommand(PSCommand psCommand, PowerShellExecutionOptions executionOptions, CancellationToken cancellationToken) - => InvokePSCommand(psCommand, executionOptions, cancellationToken); + { + InvokePSCommand(psCommand, executionOptions, cancellationToken); + } public TResult InvokePSDelegate(string representation, ExecutionOptions executionOptions, Func func, CancellationToken cancellationToken) { @@ -662,7 +667,7 @@ private void DoOneRepl(CancellationToken cancellationToken) private string GetPrompt(CancellationToken cancellationToken) { var command = new PSCommand().AddCommand("prompt"); - IReadOnlyList results = InvokePSCommand(command, PowerShellExecutionOptions.Default, cancellationToken); + IReadOnlyList results = InvokePSCommand(command, executionOptions: null, cancellationToken); string prompt = results.Count > 0 ? results[0] : DefaultPrompt; if (CurrentRunspace.RunspaceOrigin != RunspaceOrigin.Local) @@ -846,7 +851,7 @@ private void OnPowerShellIdle(CancellationToken idleCancellationToken) // to force event processing if (runPipelineForEventProcessing) { - InvokePSCommand(new PSCommand().AddScript("0", useLocalScope: true), PowerShellExecutionOptions.Default, CancellationToken.None); + InvokePSCommand(new PSCommand().AddScript("0", useLocalScope: true), executionOptions: null, CancellationToken.None); } } diff --git a/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs b/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs index 031727b02..fffb0c1c9 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Utility/CommandHelpers.cs @@ -183,7 +183,7 @@ public static async Task GetCommandSynopsisAsync( IEnumerable aliases = await executionService.ExecuteDelegateAsync>( nameof(GetAliasesAsync), - Execution.ExecutionOptions.Default, + executionOptions: null, (pwsh, _) => { CommandInvocationIntrinsics invokeCommand = pwsh.Runspace.SessionStateProxy.InvokeCommand; diff --git a/src/PowerShellEditorServices/Services/Workspace/RemoteFileManagerService.cs b/src/PowerShellEditorServices/Services/Workspace/RemoteFileManagerService.cs index 6db4fc4d9..4ff1b98f6 100644 --- a/src/PowerShellEditorServices/Services/Workspace/RemoteFileManagerService.cs +++ b/src/PowerShellEditorServices/Services/Workspace/RemoteFileManagerService.cs @@ -657,8 +657,8 @@ private async void HandlePSEventReceivedAsync(object sender, PSEventArgs args) private Task RegisterPSEditFunctionAsync() => _executionService.ExecuteDelegateAsync( "Register psedit function", - ExecutionOptions.Default, - (pwsh, cancellationToken) => RegisterPSEditFunction(pwsh.Runspace), + executionOptions: null, + (pwsh, _) => RegisterPSEditFunction(pwsh.Runspace), CancellationToken.None); private void RegisterPSEditFunction(Runspace runspace) From 837432bc467c7497aeca6d8e242961d8f341bc05 Mon Sep 17 00:00:00 2001 From: Andy Schwartzmeyer Date: Wed, 9 Feb 2022 16:23:40 -0800 Subject: [PATCH 006/613] Clean up LSP message tests (#1700) --- .../DebugAdapterClientExtensions.cs | 21 +- .../LanguageServerProtocolMessageTests.cs | 212 +++++++----------- 2 files changed, 90 insertions(+), 143 deletions(-) diff --git a/test/PowerShellEditorServices.Test.E2E/DebugAdapterClientExtensions.cs b/test/PowerShellEditorServices.Test.E2E/DebugAdapterClientExtensions.cs index 8fb89b79c..cc47fb6f7 100644 --- a/test/PowerShellEditorServices.Test.E2E/DebugAdapterClientExtensions.cs +++ b/test/PowerShellEditorServices.Test.E2E/DebugAdapterClientExtensions.cs @@ -14,23 +14,24 @@ public static class DebugAdapterClientExtensions { public static async Task LaunchScript(this DebugAdapterClient debugAdapterClient, string filePath, TaskCompletionSource started) { - LaunchResponse launchResponse = await debugAdapterClient.Launch(new PsesLaunchRequestArguments - { - NoDebug = false, - Script = filePath, - Cwd = "", - CreateTemporaryIntegratedConsole = false, - }).ConfigureAwait(false); + LaunchResponse launchResponse = await debugAdapterClient.Launch( + new PsesLaunchRequestArguments + { + NoDebug = false, + Script = filePath, + Cwd = "", + CreateTemporaryIntegratedConsole = false + }).ConfigureAwait(true); - if (launchResponse == null) + if (launchResponse is null) { throw new Exception("Launch response was null."); } // This will check to see if we received the Initialized event from the server. await Task.Run( - async () => await started.Task.ConfigureAwait(false), - new CancellationTokenSource(2000).Token).ConfigureAwait(false); + async () => await started.Task.ConfigureAwait(true), + new CancellationTokenSource(2000).Token).ConfigureAwait(true); } } } diff --git a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs index 15de43d4c..a59e19446 100644 --- a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs +++ b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs @@ -29,6 +29,7 @@ namespace PowerShellEditorServices.Test.E2E { + [Trait("Category", "LSP")] public class LanguageServerProtocolMessageTests : IClassFixture, IDisposable { // Borrowed from `VersionUtils` which can't be used here due to an initialization problem. @@ -41,7 +42,6 @@ public class LanguageServerProtocolMessageTests : IClassFixture private readonly List Diagnostics; private readonly List TelemetryEvents; private readonly string PwshExe; - private readonly LSPTestsFixture _fixture; public LanguageServerProtocolMessageTests(ITestOutputHelper output, LSPTestsFixture data) { @@ -51,8 +51,6 @@ public LanguageServerProtocolMessageTests(ITestOutputHelper output, LSPTestsFixt Diagnostics.Clear(); TelemetryEvents = data.TelemetryEvents; TelemetryEvents.Clear(); - _fixture = data; - PwshExe = PsesStdioProcess.PwshExe; } @@ -60,6 +58,7 @@ public void Dispose() { Diagnostics.Clear(); TelemetryEvents.Clear(); + GC.SuppressFinalize(this); } private string NewTestFile(string script, bool isPester = false, string languageId = "powershell") @@ -88,45 +87,40 @@ private string NewTestFile(string script, bool isPester = false, string language private async Task WaitForDiagnosticsAsync() { // Wait for PSSA to finish. - int i = 0; - while(Diagnostics.Count == 0) + for (int i = 0; Diagnostics.Count == 0; i++) { - if(i >= 10) + if (i >= 10) { throw new InvalidDataException("No diagnostics showed up after 20s."); } - await Task.Delay(2000).ConfigureAwait(false); - i++; + await Task.Delay(2000).ConfigureAwait(true); } } private async Task WaitForTelemetryEventsAsync() { // Wait for PSSA to finish. - int i = 0; - while(TelemetryEvents.Count == 0) + for ( int i = 0; TelemetryEvents.Count == 0; i++) { - if(i >= 10) + if (i >= 10) { throw new InvalidDataException("No telemetry events showed up after 20s."); } - await Task.Delay(2000).ConfigureAwait(false); - i++; + await Task.Delay(2000).ConfigureAwait(true); } } - [Trait("Category", "LSP")] [Fact] public async Task CanSendPowerShellGetVersionRequestAsync() { PowerShellVersion details = await PsesLanguageClient - .SendRequest("powerShell/getVersion", new GetVersionParams()) - .Returning(CancellationToken.None).ConfigureAwait(false); + .SendRequest("powerShell/getVersion", new GetVersionParams()) + .Returning(CancellationToken.None).ConfigureAwait(true); - if(PwshExe == "powershell") + if (PwshExe == "powershell") { Assert.Equal("Desktop", details.Edition); } @@ -136,11 +130,9 @@ PowerShellVersion details } } - [Trait("Category", "LSP")] [Fact] public async Task CanSendWorkspaceSymbolRequestAsync() { - NewTestFile(@" function CanSendWorkspaceSymbolRequest { Write-Host 'hello' @@ -148,19 +140,18 @@ function CanSendWorkspaceSymbolRequest { "); Container symbols = await PsesLanguageClient - .SendRequest( + .SendRequest( "workspace/symbol", new WorkspaceSymbolParams { Query = "CanSendWorkspaceSymbolRequest" }) - .Returning>(CancellationToken.None).ConfigureAwait(false); + .Returning>(CancellationToken.None).ConfigureAwait(true); SymbolInformation symbol = Assert.Single(symbols); Assert.Equal("CanSendWorkspaceSymbolRequest { }", symbol.Name); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanReceiveDiagnosticsFromFileOpenAsync() { @@ -169,23 +160,21 @@ public async Task CanReceiveDiagnosticsFromFileOpenAsync() "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); NewTestFile("$a = 4"); - await WaitForDiagnosticsAsync().ConfigureAwait(false); + await WaitForDiagnosticsAsync().ConfigureAwait(true); Diagnostic diagnostic = Assert.Single(Diagnostics); Assert.Equal("PSUseDeclaredVarsMoreThanAssignments", diagnostic.Code); } - [Trait("Category", "LSP")] [Fact] public async Task WontReceiveDiagnosticsFromFileOpenThatIsNotPowerShellAsync() { NewTestFile("$a = 4", languageId: "plaintext"); - await Task.Delay(2000).ConfigureAwait(false); + await Task.Delay(2000).ConfigureAwait(true); Assert.Empty(Diagnostics); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanReceiveDiagnosticsFromFileChangedAsync() { @@ -194,7 +183,7 @@ public async Task CanReceiveDiagnosticsFromFileChangedAsync() "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); string filePath = NewTestFile("$a = 4"); - await WaitForDiagnosticsAsync().ConfigureAwait(false); + await WaitForDiagnosticsAsync().ConfigureAwait(true); Diagnostics.Clear(); PsesLanguageClient.SendNotification("textDocument/didChange", new DidChangeTextDocumentParams @@ -222,7 +211,7 @@ public async Task CanReceiveDiagnosticsFromFileChangedAsync() } }); - await WaitForDiagnosticsAsync().ConfigureAwait(false); + await WaitForDiagnosticsAsync().ConfigureAwait(true); if (Diagnostics.Count > 1) { StringBuilder errorBuilder = new StringBuilder().AppendLine("Multiple diagnostics found when there should be only 1:"); @@ -238,7 +227,6 @@ public async Task CanReceiveDiagnosticsFromFileChangedAsync() Assert.Equal("PSUseDeclaredVarsMoreThanAssignments", diagnostic.Code); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanReceiveDiagnosticsFromConfigurationChangeAsync() { @@ -247,7 +235,7 @@ public async Task CanReceiveDiagnosticsFromConfigurationChangeAsync() "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); NewTestFile("gci | % { $_ }"); - await WaitForDiagnosticsAsync().ConfigureAwait(false); + await WaitForDiagnosticsAsync().ConfigureAwait(true); // NewTestFile doesn't clear diagnostic notifications so we need to do that for this test. Diagnostics.Clear(); @@ -269,7 +257,7 @@ public async Task CanReceiveDiagnosticsFromConfigurationChangeAsync() }) }); - await WaitForTelemetryEventsAsync().ConfigureAwait(false); + await WaitForTelemetryEventsAsync().ConfigureAwait(true); var telemetryEvent = Assert.Single(TelemetryEvents); Assert.Equal("NonDefaultPsesFeatureConfiguration", telemetryEvent.EventName); Assert.False((bool)telemetryEvent.Data.GetValue("ScriptAnalysis")); @@ -294,12 +282,11 @@ public async Task CanReceiveDiagnosticsFromConfigurationChangeAsync() }); // Wait a bit to make sure no telemetry events came through - await Task.Delay(2000).ConfigureAwait(false); + await Task.Delay(2000).ConfigureAwait(true); // Since we have default settings we should not get any telemetry events about Assert.Empty(TelemetryEvents.Where(e => e.EventName == "NonDefaultPsesFeatureConfiguration")); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendFoldingRangeRequestAsync() { @@ -313,7 +300,7 @@ public async Task CanSendFoldingRangeRequestAsync() Container foldingRanges = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/foldingRange", new FoldingRangeRequestParam { @@ -322,7 +309,7 @@ await PsesLanguageClient Uri = new Uri(scriptPath) } }) - .Returning>(CancellationToken.None).ConfigureAwait(false); + .Returning>(CancellationToken.None).ConfigureAwait(true); Assert.Collection(foldingRanges.OrderBy(f => f.StartLine), range1 => @@ -341,7 +328,6 @@ await PsesLanguageClient }); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanSendFormattingRequestAsync() { @@ -357,7 +343,7 @@ public async Task CanSendFormattingRequestAsync() "); TextEditContainer textEdits = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/formatting", new DocumentFormattingParams { @@ -371,7 +357,7 @@ public async Task CanSendFormattingRequestAsync() InsertSpaces = false } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); TextEdit textEdit = Assert.Single(textEdits); @@ -379,7 +365,6 @@ public async Task CanSendFormattingRequestAsync() Assert.Contains("\t", textEdit.NewText); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanSendRangeFormattingRequestAsync() { @@ -395,7 +380,7 @@ public async Task CanSendRangeFormattingRequestAsync() "); TextEditContainer textEdits = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/formatting", new DocumentRangeFormattingParams { @@ -422,7 +407,7 @@ public async Task CanSendRangeFormattingRequestAsync() InsertSpaces = false } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); TextEdit textEdit = Assert.Single(textEdits); @@ -430,7 +415,6 @@ public async Task CanSendRangeFormattingRequestAsync() Assert.Contains("\t", textEdit.NewText); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendDocumentSymbolRequestAsync() { @@ -444,7 +428,7 @@ function CanSendDocumentSymbolRequest { SymbolInformationOrDocumentSymbolContainer symbolInformationOrDocumentSymbols = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/documentSymbol", new DocumentSymbolParams { @@ -453,7 +437,7 @@ await PsesLanguageClient Uri = new Uri(scriptPath) } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Collection(symbolInformationOrDocumentSymbols, symInfoOrDocSym => { @@ -466,7 +450,6 @@ await PsesLanguageClient }); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendReferencesRequestAsync() { @@ -479,7 +462,7 @@ function CanSendReferencesRequest { "); LocationContainer locations = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/references", new ReferenceParams { @@ -497,7 +480,7 @@ function CanSendReferencesRequest { IncludeDeclaration = false } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Collection(locations, location1 => @@ -507,7 +490,6 @@ function CanSendReferencesRequest { Assert.Equal(9, range.Start.Character); Assert.Equal(1, range.End.Line); Assert.Equal(33, range.End.Character); - }, location2 => { @@ -519,7 +501,6 @@ function CanSendReferencesRequest { }); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendDocumentHighlightRequestAsync() { @@ -531,7 +512,7 @@ public async Task CanSendDocumentHighlightRequestAsync() DocumentHighlightContainer documentHighlights = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/documentHighlight", new DocumentHighlightParams { @@ -545,7 +526,7 @@ await PsesLanguageClient Character = 1 } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Collection(documentHighlights, documentHighlight1 => @@ -555,7 +536,6 @@ await PsesLanguageClient Assert.Equal(0, range.Start.Character); Assert.Equal(1, range.End.Line); Assert.Equal(10, range.End.Character); - }, documentHighlight2 => { @@ -567,7 +547,6 @@ await PsesLanguageClient }); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendPowerShellGetPSHostProcessesRequestAsync() { @@ -595,10 +574,10 @@ public async Task CanSendPowerShellGetPSHostProcessesRequestAsync() { pSHostProcessResponses = await PsesLanguageClient - .SendRequest( + .SendRequest( "powerShell/getPSHostProcesses", - new GetPSHostProcesssesParams { }) - .Returning(CancellationToken.None).ConfigureAwait(false); + new GetPSHostProcesssesParams()) + .Returning(CancellationToken.None).ConfigureAwait(true); } finally { @@ -609,7 +588,6 @@ await PsesLanguageClient Assert.NotEmpty(pSHostProcessResponses); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendPowerShellGetRunspaceRequestAsync() { @@ -636,13 +614,13 @@ public async Task CanSendPowerShellGetRunspaceRequestAsync() { runspaceResponses = await PsesLanguageClient - .SendRequest( + .SendRequest( "powerShell/getRunspace", new GetRunspaceParams { ProcessId = $"{process.Id}" }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); } finally { @@ -653,7 +631,6 @@ await PsesLanguageClient Assert.NotEmpty(runspaceResponses); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendPesterLegacyCodeLensRequestAsync() { @@ -684,7 +661,7 @@ public async Task CanSendPesterLegacyCodeLensRequestAsync() ", isPester: true); CodeLensContainer codeLenses = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/codeLens", new CodeLensParams { @@ -693,7 +670,7 @@ public async Task CanSendPesterLegacyCodeLensRequestAsync() Uri = new Uri(filePath) } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Collection(codeLenses, codeLens1 => @@ -720,7 +697,6 @@ public async Task CanSendPesterLegacyCodeLensRequestAsync() }); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendPesterCodeLensRequestAsync() { @@ -751,7 +727,7 @@ public async Task CanSendPesterCodeLensRequestAsync() ", isPester: true); CodeLensContainer codeLenses = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/codeLens", new CodeLensParams { @@ -760,7 +736,7 @@ public async Task CanSendPesterCodeLensRequestAsync() Uri = new Uri(filePath) } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Collection(codeLenses, codeLens => @@ -831,7 +807,6 @@ public async Task CanSendPesterCodeLensRequestAsync() }); } - [Trait("Category", "LSP")] [Fact] public async Task NoMessageIfPesterCodeLensDisabled() { @@ -861,7 +836,7 @@ public async Task NoMessageIfPesterCodeLensDisabled() ", isPester: true); CodeLensContainer codeLenses = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/codeLens", new CodeLensParams { @@ -870,12 +845,11 @@ public async Task NoMessageIfPesterCodeLensDisabled() Uri = new Uri(filePath) } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Empty(codeLenses); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendReferencesCodeLensRequestAsync() { @@ -888,7 +862,7 @@ function CanSendReferencesCodeLensRequest { "); CodeLensContainer codeLenses = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/codeLens", new CodeLensParams { @@ -897,7 +871,7 @@ function CanSendReferencesCodeLensRequest { Uri = new Uri(filePath) } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); CodeLens codeLens = Assert.Single(codeLenses); @@ -908,13 +882,12 @@ function CanSendReferencesCodeLensRequest { Assert.Equal(1, range.End.Character); CodeLens codeLensResolveResult = await PsesLanguageClient - .SendRequest("codeLens/resolve", codeLens) - .Returning(CancellationToken.None).ConfigureAwait(false); + .SendRequest("codeLens/resolve", codeLens) + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Equal("1 reference", codeLensResolveResult.Command.Title); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanSendCodeActionRequestAsync() { @@ -923,11 +896,11 @@ public async Task CanSendCodeActionRequestAsync() "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); string filePath = NewTestFile("gci"); - await WaitForDiagnosticsAsync().ConfigureAwait(false); + await WaitForDiagnosticsAsync().ConfigureAwait(true); CommandOrCodeActionContainer commandOrCodeActions = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/codeAction", new CodeActionParams { @@ -951,7 +924,7 @@ await PsesLanguageClient Diagnostics = new Container(Diagnostics) } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Collection(commandOrCodeActions, command => @@ -972,7 +945,6 @@ await PsesLanguageClient }); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanSendCompletionAndCompletionResolveRequestAsync() { @@ -993,24 +965,23 @@ public async Task CanSendCompletionAndCompletionResolveRequestAsync() completionItem1 => completionItem1.Label == "Write-Host"); CompletionItem updatedCompletionItem = await PsesLanguageClient - .SendRequest("completionItem/resolve", completionItem) - .Returning(CancellationToken.None).ConfigureAwait(false); + .SendRequest("completionItem/resolve", completionItem) + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Contains("Writes customized output to a host", updatedCompletionItem.Documentation.String); } - [Trait("Category", "LSP")] [SkippableFact(Skip = "This test is too flaky right now.")] public async Task CanSendCompletionResolveWithModulePrefixRequestAsync() { await PsesLanguageClient - .SendRequest( + .SendRequest( "evaluate", new EvaluateRequestArguments { Expression = "Import-Module Microsoft.PowerShell.Archive -Prefix Slow" }) - .ReturningVoid(CancellationToken.None).ConfigureAwait(false); + .ReturningVoid(CancellationToken.None).ConfigureAwait(true); string filePath = NewTestFile("Expand-SlowArch"); @@ -1028,13 +999,12 @@ await PsesLanguageClient completionItem1 => completionItem1.Label == "Expand-SlowArchive"); CompletionItem updatedCompletionItem = await PsesLanguageClient - .SendRequest("completionItem/resolve", completionItem) - .Returning(CancellationToken.None).ConfigureAwait(false); + .SendRequest("completionItem/resolve", completionItem) + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Contains("Extracts files from a specified archive", updatedCompletionItem.Documentation.String); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanSendHoverRequestAsync() { @@ -1049,14 +1019,11 @@ public async Task CanSendHoverRequestAsync() Uri = DocumentUri.FromFileSystemPath(filePath) }, Position = new Position(line: 0, character: 1) - }).ConfigureAwait(false); + }).ConfigureAwait(true); Assert.True(hover.Contents.HasMarkedStrings); Assert.Collection(hover.Contents.MarkedStrings, - str1 => - { - Assert.Equal("function Write-Host", str1.Value); - }, + str1 => Assert.Equal("function Write-Host", str1.Value), str2 => { Assert.Equal("markdown", str2.Language); @@ -1064,14 +1031,13 @@ public async Task CanSendHoverRequestAsync() }); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendSignatureHelpRequestAsync() { string filePath = NewTestFile("Get-Date "); SignatureHelp signatureHelp = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/signatureHelp", new SignatureHelpParams { @@ -1085,12 +1051,11 @@ public async Task CanSendSignatureHelpRequestAsync() Character = 9 } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Contains("Get-Date", signatureHelp.Signatures.First().Label); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendDefinitionRequestAsync() { @@ -1104,21 +1069,14 @@ function CanSendDefinitionRequest { LocationOrLocationLinks locationOrLocationLinks = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/definition", new DefinitionParams { - TextDocument = new TextDocumentIdentifier - { - Uri = new Uri(scriptPath) - }, - Position = new Position - { - Line = 5, - Character = 2 - } + TextDocument = new TextDocumentIdentifier { Uri = new Uri(scriptPath) }, + Position = new Position { Line = 5, Character = 2 } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); LocationOrLocationLink locationOrLocationLink = Assert.Single(locationOrLocationLinks); @@ -1129,7 +1087,6 @@ await PsesLanguageClient Assert.Equal(33, locationOrLocationLink.Location.Range.End.Character); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanSendGetProjectTemplatesRequestAsync() { @@ -1137,26 +1094,19 @@ public async Task CanSendGetProjectTemplatesRequestAsync() GetProjectTemplatesResponse getProjectTemplatesResponse = await PsesLanguageClient - .SendRequest( + .SendRequest( "powerShell/getProjectTemplates", new GetProjectTemplatesRequest { IncludeInstalledModules = true }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Collection(getProjectTemplatesResponse.Templates.OrderBy(t => t.Title), - template1 => - { - Assert.Equal("AddPSScriptAnalyzerSettings", template1.Title); - }, - template2 => - { - Assert.Equal("New PowerShell Manifest Module", template2.Title); - }); + template1 => Assert.Equal("AddPSScriptAnalyzerSettings", template1.Title), + template2 => Assert.Equal("New PowerShell Manifest Module", template2.Title)); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanSendGetCommentHelpRequestAsync() { @@ -1179,7 +1129,7 @@ function CanSendGetCommentHelpRequest { CommentHelpRequestResult commentHelpRequestResult = await PsesLanguageClient - .SendRequest( + .SendRequest( "powerShell/getCommentHelp", new CommentHelpRequestParams { @@ -1191,13 +1141,12 @@ await PsesLanguageClient Character = 0 } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.NotEmpty(commentHelpRequestResult.Content); Assert.Contains("myParam", commentHelpRequestResult.Content[7]); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendEvaluateRequestAsync() { @@ -1205,34 +1154,32 @@ public async Task CanSendEvaluateRequestAsync() EvaluateResponseBody evaluateResponseBody = await PsesLanguageClient - .SendRequest( + .SendRequest( "evaluate", new EvaluateRequestArguments { Expression = "Get-ChildItem" }) - .Returning(cancellationSource.Token).ConfigureAwait(false); + .Returning(cancellationSource.Token).ConfigureAwait(true); // These always gets returned so this test really just makes sure we get _any_ response. Assert.Equal("", evaluateResponseBody.Result); Assert.Equal(0, evaluateResponseBody.VariablesReference); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendGetCommandRequestAsync() { List pSCommandMessages = await PsesLanguageClient - .SendRequest("powerShell/getCommand", new GetCommandParams()) - .Returning>(CancellationToken.None).ConfigureAwait(false); + .SendRequest("powerShell/getCommand", new GetCommandParams()) + .Returning>(CancellationToken.None).ConfigureAwait(true); Assert.NotEmpty(pSCommandMessages); // There should be at least 20 commands or so. Assert.True(pSCommandMessages.Count > 20); } - [Trait("Category", "LSP")] [SkippableFact] public async Task CanSendExpandAliasRequestAsync() { @@ -1242,27 +1189,26 @@ public async Task CanSendExpandAliasRequestAsync() ExpandAliasResult expandAliasResult = await PsesLanguageClient - .SendRequest( + .SendRequest( "powerShell/expandAlias", new ExpandAliasParams { Text = "gci" }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); Assert.Equal("Get-ChildItem", expandAliasResult.Text); } - [Trait("Category", "LSP")] [Fact] public async Task CanSendSemanticTokenRequestAsync() { - string scriptContent = "function"; + const string scriptContent = "function"; string scriptPath = NewTestFile(scriptContent); SemanticTokens result = await PsesLanguageClient - .SendRequest( + .SendRequest( "textDocument/semanticTokens/full", new SemanticTokensParams { @@ -1271,7 +1217,7 @@ await PsesLanguageClient Uri = new Uri(scriptPath) } }) - .Returning(CancellationToken.None).ConfigureAwait(false); + .Returning(CancellationToken.None).ConfigureAwait(true); // More information about how this data is generated can be found at // https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 From d9e6fb5f1cceb45a8ea7a05f3af5ce337104dbfe Mon Sep 17 00:00:00 2001 From: Andy Schwartzmeyer Date: Thu, 10 Feb 2022 09:50:29 -0800 Subject: [PATCH 007/613] Clean up breakpoint files (#1701) --- .../DebugAdapter/BreakpointService.cs | 102 ++++++++---------- .../Services/DebugAdapter/DebugService.cs | 2 +- .../Debugging/BreakpointApiUtils.cs | 43 ++++---- .../Debugging/BreakpointDetails.cs | 6 +- 4 files changed, 70 insertions(+), 83 deletions(-) diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs index 1718c3168..d978b67e5 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs @@ -23,11 +23,9 @@ internal class BreakpointService private readonly DebugStateService _debugStateService; // TODO: This needs to be managed per nested session - internal readonly Dictionary> BreakpointsPerFile = - new Dictionary>(); + internal readonly Dictionary> BreakpointsPerFile = new(); - internal readonly HashSet CommandBreakpoints = - new HashSet(); + internal readonly HashSet CommandBreakpoints = new(); public BreakpointService( ILoggerFactory factory, @@ -51,9 +49,11 @@ public async Task> GetBreakpointsAsync() } // Legacy behavior - PSCommand psCommand = new PSCommand() - .AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint"); - IEnumerable breakpoints = await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); + PSCommand psCommand = new PSCommand().AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint"); + IEnumerable breakpoints = await _executionService + .ExecutePSCommandAsync(psCommand, CancellationToken.None) + .ConfigureAwait(false); + return breakpoints.ToList(); } @@ -73,13 +73,12 @@ public async Task> SetBreakpointsAsync(string esc breakpointDetails.Verified = false; } } - return breakpoints; } // Legacy behavior PSCommand psCommand = null; - List configuredBreakpoints = new List(); + List configuredBreakpoints = new(); foreach (BreakpointDetails breakpoint in breakpoints) { ScriptBlock actionScriptBlock = null; @@ -106,7 +105,7 @@ public async Task> SetBreakpointsAsync(string esc // On first iteration psCommand will be null, every subsequent // iteration will need to start a new statement. - if (psCommand == null) + if (psCommand is null) { psCommand = new PSCommand(); } @@ -121,7 +120,7 @@ public async Task> SetBreakpointsAsync(string esc .AddParameter("Line", breakpoint.LineNumber); // Check if the user has specified the column number for the breakpoint. - if (breakpoint.ColumnNumber.HasValue && breakpoint.ColumnNumber.Value > 0) + if (breakpoint.ColumnNumber > 0) { // It bums me out that PowerShell will silently ignore a breakpoint // where either the line or the column is invalid. I'd rather have an @@ -129,26 +128,24 @@ public async Task> SetBreakpointsAsync(string esc psCommand.AddParameter("Column", breakpoint.ColumnNumber.Value); } - if (actionScriptBlock != null) + if (actionScriptBlock is not null) { psCommand.AddParameter("Action", actionScriptBlock); } } // If no PSCommand was created then there are no breakpoints to set. - if (psCommand != null) + if (psCommand is not null) { - IEnumerable setBreakpoints = - await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); - configuredBreakpoints.AddRange( - setBreakpoints.Select((breakpoint) => BreakpointDetails.Create(breakpoint)) - ); + IEnumerable setBreakpoints = await _executionService + .ExecutePSCommandAsync(psCommand, CancellationToken.None) + .ConfigureAwait(false); + configuredBreakpoints.AddRange(setBreakpoints.Select((breakpoint) => BreakpointDetails.Create(breakpoint))); } - return configuredBreakpoints; } - public async Task> SetCommandBreakpoints(IEnumerable breakpoints) + public async Task> SetCommandBreakpointsAsync(IEnumerable breakpoints) { if (BreakpointApiUtils.SupportsBreakpointApis(_editorServicesHost.CurrentRunspace)) { @@ -156,26 +153,28 @@ public async Task> SetCommandBreakpoints(I { try { - BreakpointApiUtils.SetBreakpoint(_editorServicesHost.Runspace.Debugger, commandBreakpointDetails, _debugStateService.RunspaceId); + BreakpointApiUtils.SetBreakpoint( + _editorServicesHost.Runspace.Debugger, + commandBreakpointDetails, + _debugStateService.RunspaceId); } - catch(InvalidOperationException e) + catch (InvalidOperationException e) { commandBreakpointDetails.Message = e.Message; commandBreakpointDetails.Verified = false; } } - return breakpoints; } // Legacy behavior PSCommand psCommand = null; - List configuredBreakpoints = new List(); + List configuredBreakpoints = new(); foreach (CommandBreakpointDetails breakpoint in breakpoints) { // On first iteration psCommand will be null, every subsequent // iteration will need to start a new statement. - if (psCommand == null) + if (psCommand is null) { psCommand = new PSCommand(); } @@ -208,20 +207,18 @@ public async Task> SetCommandBreakpoints(I configuredBreakpoints.Add(breakpoint); continue; } - psCommand.AddParameter("Action", actionScriptBlock); } } // If no PSCommand was created then there are no breakpoints to set. - if (psCommand != null) + if (psCommand is not null) { - IEnumerable setBreakpoints = - await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); - configuredBreakpoints.AddRange( - setBreakpoints.Select(CommandBreakpointDetails.Create)); + IEnumerable setBreakpoints = await _executionService + .ExecutePSCommandAsync(psCommand, CancellationToken.None) + .ConfigureAwait(false); + configuredBreakpoints.AddRange(setBreakpoints.Select(CommandBreakpointDetails.Create)); } - return configuredBreakpoints; } @@ -238,7 +235,7 @@ public async Task RemoveAllBreakpointsAsync(string scriptPath = null) _editorServicesHost.Runspace.Debugger, _debugStateService.RunspaceId)) { - if (scriptPath == null || scriptPath == breakpoint.Script) + if (scriptPath is null || scriptPath == breakpoint.Script) { BreakpointApiUtils.RemoveBreakpoint( _editorServicesHost.Runspace.Debugger, @@ -246,14 +243,11 @@ public async Task RemoveAllBreakpointsAsync(string scriptPath = null) _debugStateService.RunspaceId); } } - return; } // Legacy behavior - - PSCommand psCommand = new PSCommand(); - psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint"); + var psCommand = new PSCommand().AddCommand(@"Microsoft.PowerShell.Utility\Get-PSBreakpoint"); if (!string.IsNullOrEmpty(scriptPath)) { @@ -261,7 +255,6 @@ public async Task RemoveAllBreakpointsAsync(string scriptPath = null) } psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint"); - await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); } catch (Exception e) @@ -281,37 +274,26 @@ public async Task RemoveBreakpointsAsync(IEnumerable breakpoints) breakpoint, _debugStateService.RunspaceId); - switch (breakpoint) + _ = breakpoint switch { - case CommandBreakpoint commandBreakpoint: - CommandBreakpoints.Remove(commandBreakpoint); - break; - case LineBreakpoint lineBreakpoint: - if (BreakpointsPerFile.TryGetValue(lineBreakpoint.Script, out HashSet bps)) - { - bps.Remove(lineBreakpoint); - } - break; - default: - throw new ArgumentException("Unsupported breakpoint type."); - } + CommandBreakpoint commandBreakpoint => CommandBreakpoints.Remove(commandBreakpoint), + LineBreakpoint lineBreakpoint => + BreakpointsPerFile.TryGetValue(lineBreakpoint.Script, out HashSet bps) && bps.Remove(lineBreakpoint), + _ => throw new NotImplementedException("Other breakpoints not supported yet"), + }; } - return; } // Legacy behavior - var breakpointIds = breakpoints.Select(b => b.Id).ToArray(); - if(breakpointIds.Length > 0) + var breakpointIds = breakpoints.Select(b => b.Id); + if (breakpointIds.Any()) { - PSCommand psCommand = new PSCommand(); - psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint"); - psCommand.AddParameter("Id", breakpoints.Select(b => b.Id).ToArray()); - + PSCommand psCommand = new PSCommand() + .AddCommand(@"Microsoft.PowerShell.Utility\Remove-PSBreakpoint") + .AddParameter("Id", breakpoints.Select(b => b.Id).ToArray()); await _executionService.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(false); } } - - } } diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs index 383ecf4fa..680f81be6 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs @@ -185,7 +185,7 @@ public async Task SetCommandBreakpointsAsync( if (breakpoints.Length > 0) { - resultBreakpointDetails = (await _breakpointService.SetCommandBreakpoints(breakpoints).ConfigureAwait(false)).ToArray(); + resultBreakpointDetails = (await _breakpointService.SetCommandBreakpointsAsync(breakpoints).ConfigureAwait(false)).ToArray(); } return resultBreakpointDetails ?? Array.Empty(); diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs index 82eacfe73..f05a96358 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs @@ -134,17 +134,24 @@ public static Breakpoint SetBreakpoint(Debugger debugger, BreakpointDetailsBase } } - switch (breakpoint) + return breakpoint switch { - case BreakpointDetails lineBreakpoint: - return SetLineBreakpointDelegate(debugger, lineBreakpoint.Source, lineBreakpoint.LineNumber, lineBreakpoint.ColumnNumber ?? 0, actionScriptBlock, runspaceId); - - case CommandBreakpointDetails commandBreakpoint: - return SetCommandBreakpointDelegate(debugger, commandBreakpoint.Name, null, null, runspaceId); - - default: - throw new NotImplementedException("Other breakpoints not supported yet"); - } + BreakpointDetails lineBreakpoint => SetLineBreakpointDelegate( + debugger, + lineBreakpoint.Source, + lineBreakpoint.LineNumber, + lineBreakpoint.ColumnNumber ?? 0, + actionScriptBlock, + runspaceId), + + CommandBreakpointDetails commandBreakpoint => SetCommandBreakpointDelegate(debugger, + commandBreakpoint.Name, + null, + null, + runspaceId), + + _ => throw new NotImplementedException("Other breakpoints not supported yet"), + }; } public static List GetBreakpoints(Debugger debugger, int? runspaceId = null) @@ -173,20 +180,20 @@ public static ScriptBlock GetBreakpointActionScriptBlock(string condition, strin try { - StringBuilder builder = new StringBuilder( + StringBuilder builder = new( string.IsNullOrEmpty(logMessage) ? "break" : $"Microsoft.PowerShell.Utility\\Write-Host \"{logMessage.Replace("\"","`\"")}\""); // If HitCondition specified, parse and verify it. - if (!(string.IsNullOrWhiteSpace(hitCondition))) + if (!string.IsNullOrWhiteSpace(hitCondition)) { if (!int.TryParse(hitCondition, out int parsedHitCount)) { throw new InvalidOperationException("Hit Count was not a valid integer."); } - if(string.IsNullOrWhiteSpace(condition)) + if (string.IsNullOrWhiteSpace(condition)) { // In the HitCount only case, this is simple as we can just use the HitCount // property on the breakpoint object which is represented by $_. @@ -217,8 +224,7 @@ public static ScriptBlock GetBreakpointActionScriptBlock(string condition, strin // Check for "advanced" condition syntax i.e. if the user has specified // a "break" or "continue" statement anywhere in their scriptblock, // pass their scriptblock through to the Action parameter as-is. - if (parsed.Ast.Find(ast => - (ast is BreakStatementAst || ast is ContinueStatementAst), true) != null) + if (parsed.Ast.Find(ast => ast is BreakStatementAst || ast is ContinueStatementAst, true) is not null) { return parsed; } @@ -247,10 +253,9 @@ private static bool ValidateBreakpointConditionAst(Ast conditionAst, out string // We are only inspecting a few simple scenarios in the EndBlock only. if (conditionAst is ScriptBlockAst scriptBlockAst && - scriptBlockAst.BeginBlock == null && - scriptBlockAst.ProcessBlock == null && - scriptBlockAst.EndBlock != null && - scriptBlockAst.EndBlock.Statements.Count == 1) + scriptBlockAst.BeginBlock is null && + scriptBlockAst.ProcessBlock is null && + scriptBlockAst.EndBlock?.Statements.Count == 1) { StatementAst statementAst = scriptBlockAst.EndBlock.Statements[0]; string condition = statementAst.Extent.Text; diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs index f1c4c7bbe..4147babb1 100644 --- a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs +++ b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs @@ -30,7 +30,7 @@ internal class BreakpointDetails : BreakpointDetailsBase public int LineNumber { get; private set; } /// - /// Gets the column number at which the breakpoint is set. If null, the default of 1 is used. + /// Gets the column number at which the breakpoint is set. /// public int? ColumnNumber { get; private set; } @@ -83,9 +83,9 @@ internal static BreakpointDetails Create( Breakpoint breakpoint, BreakpointUpdateType updateType = BreakpointUpdateType.Set) { - Validate.IsNotNull("breakpoint", breakpoint); + Validate.IsNotNull(nameof(breakpoint), breakpoint); - if (!(breakpoint is LineBreakpoint lineBreakpoint)) + if (breakpoint is not LineBreakpoint lineBreakpoint) { throw new ArgumentException( "Unexpected breakpoint type: " + breakpoint.GetType().Name); From c1235574a287380072daf1b3966b10ecb2317240 Mon Sep 17 00:00:00 2001 From: Andy Schwartzmeyer Date: Mon, 14 Feb 2022 15:00:25 -0800 Subject: [PATCH 008/613] Add SBOM template (#1705) --- .vsts-ci/templates/ci-general.yml | 27 +++++++++++++++++++------- .vsts-ci/templates/release-general.yml | 21 ++++++++++++++++++-- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/.vsts-ci/templates/ci-general.yml b/.vsts-ci/templates/ci-general.yml index 763a07d33..e294564ed 100644 --- a/.vsts-ci/templates/ci-general.yml +++ b/.vsts-ci/templates/ci-general.yml @@ -17,10 +17,17 @@ steps: filePath: tools/azurePipelinesBuild.ps1 pwsh: ${{ parameters.pwsh }} +- task: PublishTestResults@2 + displayName: Publish test results + inputs: + testRunner: VSTest + testResultsFiles: '**/*.trx' + condition: succeededOrFailed() + # NOTE: We zip the artifacts because they're ~20 MB compressed, but ~300 MB raw, # and we have limited pipeline artifact storage space. - task: ArchiveFiles@2 - displayName: Zip pipeline artifacts + displayName: Zip build output inputs: rootFolderOrFile: module includeRootFolder: false @@ -30,11 +37,17 @@ steps: - publish: PowerShellEditorServices-Build.zip artifact: PowerShellEditorServices-Build-$(System.JobId) - displayName: Publish unsigned pipeline artifacts + displayName: Publish build output archive -- task: PublishTestResults@2 - displayName: Publish test results +- task: ArchiveFiles@2 + displayName: Zip sources with `project.assets.json` inputs: - testRunner: VSTest - testResultsFiles: '**/*.trx' - condition: succeededOrFailed() + rootFolderOrFile: src + includeRootFolder: false + archiveType: zip + archiveFile: PowerShellEditorServices-Sources.zip + verbose: true + +- publish: PowerShellEditorServices-Sources.zip + artifact: PowerShellEditorServices-Sources-$(System.JobId) + displayName: Publish sources archive diff --git a/.vsts-ci/templates/release-general.yml b/.vsts-ci/templates/release-general.yml index 7ef4e1479..4b531a78f 100644 --- a/.vsts-ci/templates/release-general.yml +++ b/.vsts-ci/templates/release-general.yml @@ -48,6 +48,23 @@ steps: **/Serilog*.dll **/UnixConsoleEcho.dll +# The SBOM generation requires our original sources with the `dotnet restore` +# produced `project.assets.json` files. +- task: ExtractFiles@1 + displayName: Extract source artifacts + inputs: + archiveFilePatterns: $(Pipeline.Workspace)/PowerShellEditorServices-Sources-*/PowerShellEditorServices-Sources.zip + destinationFolder: $(Pipeline.Workspace)/Sources + cleanDestinationFolder: true + +- template: Sbom.yml@ComplianceRepo + parameters: + BuildDropPath: $(Pipeline.Workspace)/ThirdPartySigned + Build_Repository_Uri: https://github.com/PowerShell/PowerShellEditorServices.git + packageName: PowerShellEditorServices + packageVersion: $(System.JobId) + sourceScanPath: $(Pipeline.Workspace)/Sources + - task: ArchiveFiles@2 displayName: Zip signed artifacts inputs: @@ -65,8 +82,8 @@ steps: # binskim AnalyzeTarget: $(Pipeline.Workspace)/*.dll AnalyzeSymPath: 'SRV*' - # component-governance - sourceScanPath: $(Build.SourcesDirectory)/PowerShellEditorServices + # component-governance: requires the `project.assets.json` files + sourceScanPath: $(Pipeline.Workspace)/Sources # credscan suppressionsFile: '' # TermCheck AKA PoliCheck From 506c6db295ee2c95601ac84b0051cee5912423c4 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 15 Feb 2022 13:11:38 -0800 Subject: [PATCH 009/613] Remove `ArgumentEscaping.Escape` for launch script arguments Attempting to be "helpful" by escaping arguments proved to cause more issues than it solved. We can instead massively simplify our script launching logic (and fix yet another test that had a "maybe bug") by just launching what the user gave us. This should also be easier for the user to debug. --- .../Utility/ArgumentUtils.cs | 40 ----------- .../Utility/PSCommandExtensions.cs | 20 +----- .../Debugging/DebugServiceTests.cs | 15 ++-- .../Utility/ArgumentEscapingTests.cs | 69 ------------------- 4 files changed, 13 insertions(+), 131 deletions(-) delete mode 100644 src/PowerShellEditorServices/Utility/ArgumentUtils.cs delete mode 100644 test/PowerShellEditorServices.Test/Utility/ArgumentEscapingTests.cs diff --git a/src/PowerShellEditorServices/Utility/ArgumentUtils.cs b/src/PowerShellEditorServices/Utility/ArgumentUtils.cs deleted file mode 100644 index dd73f4d52..000000000 --- a/src/PowerShellEditorServices/Utility/ArgumentUtils.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Text; -using System.Management.Automation.Language; - -namespace Microsoft.PowerShell.EditorServices.Utility -{ - internal static class ArgumentEscaping - { - /// - /// Escape a PowerShell argument while still making it able to be evaluated in AddScript. - /// - /// NOTE: This does not "sanitize" parameters, e.g., a pipe in one argument might affect another argument. - /// This is intentional to give flexibility to specifying arguments. - /// It also does not try to fix invalid PowerShell syntax, e.g., a single quote in a string literal. - /// - public static string Escape(string Arg) - { - // if argument is a scriptblock return as-is - if (Arg.StartsWith("{") && Arg.EndsWith("}")) - { - return Arg; - } - - // If argument has a space enclose it in quotes unless it is already quoted - if (Arg.Contains(" ")) - { - if (Arg.StartsWith("\"") && Arg.EndsWith("\"") || Arg.StartsWith("'") && Arg.EndsWith("'")) - { - return Arg; - } - - return "\"" + Arg + "\""; - } - - return Arg; - } - } -} diff --git a/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs b/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs index bc5a53d05..1d5186184 100644 --- a/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs +++ b/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs @@ -129,25 +129,11 @@ private static StringBuilder AddCommandText(this StringBuilder sb, Command comma return sb; } - public static PSCommand BuildCommandFromArguments(string command, IReadOnlyList arguments) + public static PSCommand BuildCommandFromArguments(string command, IEnumerable arguments) { // HACK: We use AddScript instead of AddArgument/AddParameter to reuse Powershell parameter binding logic. - // We quote the command parameter so that expressions can still be used in the arguments. - var sb = new StringBuilder() - .Append('.') - .Append(' ') - .Append('"') - .Append(command) - .Append('"'); - - foreach (string arg in arguments ?? System.Linq.Enumerable.Empty()) - { - sb - .Append(' ') - .Append(ArgumentEscaping.Escape(arg)); - } - - return new PSCommand().AddScript(sb.ToString()); + string script = string.Concat(". ", command, " ", string.Join(" ", arguments ?? Array.Empty())); + return new PSCommand().AddScript(script); } } } diff --git a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs index 00996db96..5013e33db 100644 --- a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs @@ -176,8 +176,16 @@ await debugService.SetCommandBreakpointsAsync( Assert.Equal("[ArrayList: 0]", var.ValueString); } - [Fact] - public async Task DebuggerAcceptsScriptArgs() + // See https://www.thomasbogholm.net/2021/06/01/convenient-member-data-sources-with-xunit/ + public static IEnumerable DebuggerAcceptsScriptArgsTestData => new List() + { + new object[] { new object[] { "Foo -Param2 @('Bar','Baz') -Force Extra1" } }, + new object[] { new object[] { "Foo", "-Param2", "@('Bar','Baz')", "-Force", "Extra1" } } + }; + + [Theory] + [MemberData(nameof(DebuggerAcceptsScriptArgsTestData))] + public async Task DebuggerAcceptsScriptArgs(string[] args) { // The path is intentionally odd (some escaped chars but not all) because we are testing // the internal path escaping mechanism - it should escape certains chars ([, ] and space) but @@ -197,9 +205,6 @@ public async Task DebuggerAcceptsScriptArgs() Assert.True(breakpoint.Verified); }); - // TODO: This test used to also pass the args as a single string, but that doesn't seem - // to work any more. Perhaps that's a bug? - var args = new[] { "Foo", "-Param2", "@('Bar','Baz')", "-Force", "Extra1" }; Task _ = ExecutePowerShellCommand(debugWithParamsFile.FilePath, args); AssertDebuggerStopped(debugWithParamsFile.FilePath, 3); diff --git a/test/PowerShellEditorServices.Test/Utility/ArgumentEscapingTests.cs b/test/PowerShellEditorServices.Test/Utility/ArgumentEscapingTests.cs deleted file mode 100644 index d6c155211..000000000 --- a/test/PowerShellEditorServices.Test/Utility/ArgumentEscapingTests.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Xunit; -using Microsoft.PowerShell.EditorServices.Utility; -using System.IO; -using System.Management.Automation; -using System.Linq; - -namespace Microsoft.PowerShell.EditorServices.Test.Session -{ - public class ArgumentEscapingTests - { - [Trait("Category", "ArgumentEscaping")] - [Theory] - [InlineData(" has spaces", "\" has spaces\"")] - [InlineData("-Parameter", "-Parameter")] - [InlineData("' single quote left alone'", "' single quote left alone'")] - [InlineData("\"double quote left alone\"", "\"double quote left alone\"")] - [InlineData("/path/to/fi le", "\"/path/to/fi le\"")] - [InlineData("'/path/to/fi le'", "'/path/to/fi le'")] - [InlineData("|pipeline", "|pipeline")] - [InlineData("am&pe rsand", "\"am&pe rsand\"")] - [InlineData("semicolon ;", "\"semicolon ;\"")] - [InlineData(": colon", "\": colon\"")] - [InlineData("$(expressions should be quoted)", "\"$(expressions should be quoted)\"")] - [InlineData("{scriptBlocks should not have escaped-spaces}", "{scriptBlocks should not have escaped-spaces}")] - [InlineData("-Parameter test", "\"-Parameter test\"")] //This is invalid, but should be obvious enough looking at the PSIC invocation - public void CorrectlyEscapesPowerShellArguments(string Arg, string expectedArg) - { - string quotedArg = ArgumentEscaping.Escape(Arg); - Assert.Equal(expectedArg, quotedArg); - } - - [Trait("Category", "ArgumentEscaping")] - [Theory] - [InlineData("/path/t o/file", "/path/t o/file")] - [InlineData("/path/with/$(echo 'expression')inline", "/path/with/expressioninline")] - [InlineData("/path/with/$(echo 'expression') inline", "/path/with/expression inline")] - [InlineData("am&per sand", "am&per sand")] - [InlineData("'inner\"\"quotes'", "inner\"\"quotes")] - public void CanEvaluateArguments(string Arg, string expectedOutput) - { - var escapedArg = ArgumentEscaping.Escape(Arg); - var psCommand = new PSCommand().AddScript($"& Write-Output {escapedArg}"); - using var pwsh = System.Management.Automation.PowerShell.Create(); - pwsh.Commands = psCommand; - var scriptOutput = pwsh.Invoke().First(); - Assert.Equal(expectedOutput, scriptOutput); - } - - [Trait("Category", "ArgumentEscaping")] - [Theory] - [InlineData("NormalScript.ps1")] - [InlineData("Bad&name4script.ps1")] - [InlineData("[Truly] b&d `Name_4_script.ps1")] - public void CanDotSourcePath(string rawFileName) - { - var ScriptAssetPath = @"..\..\..\..\PowerShellEditorServices.Test.Shared\scriptassets"; - var fullPath = Path.Combine(ScriptAssetPath, rawFileName); - var escapedPath = PathUtils.WildcardEscapePath(fullPath).ToString(); - var psCommand = new PSCommand().AddScript($"& \"{escapedPath}\""); - - using var pwsh = System.Management.Automation.PowerShell.Create(); - pwsh.Commands = psCommand; - pwsh.Invoke(); - } - } -} From 7e22c883788633118c7c2ae4fbf3c7bff5ac2318 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 9 Feb 2022 13:25:03 -0800 Subject: [PATCH 010/613] Fix running untitled scripts with arguments (but break line breakpoints) The extant hack that enabled line breakpoints in untitled scripts is untenable. It shifted the user's args by one since it ran the untitled script as the first arg to an inline script `. $args[0]` with `$args[0]` being the script contents, instead of the expected `. {