diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs index 71da2ec86..a1ccee7b5 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs @@ -216,12 +216,7 @@ public async Task TryStartAsync(HostStartOptions startOptions, Cancellatio if (startOptions.LoadProfiles) { - await ExecuteDelegateAsync( - "LoadProfiles", - new PowerShellExecutionOptions { MustRunInForeground = true, ThrowOnError = false }, - (pwsh, _) => pwsh.LoadProfiles(_hostInfo.ProfilePaths), - cancellationToken).ConfigureAwait(false); - + await LoadHostProfilesAsync(cancellationToken).ConfigureAwait(false); _logger.LogInformation("Profiles loaded"); } @@ -391,6 +386,15 @@ public void InvokePSDelegate(string representation, ExecutionOptions executionOp task.ExecuteAndGetResult(cancellationToken); } + internal Task LoadHostProfilesAsync(CancellationToken cancellationToken) + { + return ExecuteDelegateAsync( + "LoadProfiles", + new PowerShellExecutionOptions { MustRunInForeground = true, ThrowOnError = false }, + (pwsh, _) => pwsh.LoadProfiles(_hostInfo.ProfilePaths), + cancellationToken); + } + public Task SetInitialWorkingDirectoryAsync(string path, CancellationToken cancellationToken) { InitialWorkingDirectory = path; @@ -919,7 +923,7 @@ private Task PopOrReinitializeRunspaceAsync() CancellationToken.None); } - private bool TryLoadPSReadLine(PowerShell pwsh, EngineIntrinsics engineIntrinsics, out IReadLine psrlReadLine) + internal bool TryLoadPSReadLine(PowerShell pwsh, EngineIntrinsics engineIntrinsics, out IReadLine psrlReadLine) { psrlReadLine = null; try diff --git a/src/PowerShellEditorServices/Services/PowerShell/Utility/ErrorRecordExtensions.cs b/src/PowerShellEditorServices/Services/PowerShell/Utility/ErrorRecordExtensions.cs index 031a24749..41721dc12 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Utility/ErrorRecordExtensions.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Utility/ErrorRecordExtensions.cs @@ -34,7 +34,7 @@ static ErrorRecordExtensions() s_setWriteStreamProperty = Expression.Lambda>( Expression.Call( errorObjectParameter, - writeStreamProperty.GetSetMethod(), + writeStreamProperty.GetSetMethod(nonPublic: true), Expression.Constant(errorStreamType)), errorObjectParameter) .Compile(); diff --git a/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs b/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs index f2ff3771f..f671240ad 100644 --- a/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs +++ b/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs @@ -61,10 +61,13 @@ public static PSCommand AddDebugOutputCommand(this PSCommand psCommand) public static PSCommand MergePipelineResults(this PSCommand psCommand) { - // We need to do merge errors and output before rendering with an Out- cmdlet - Command lastCommand = psCommand.Commands[psCommand.Commands.Count - 1]; - lastCommand.MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output); - lastCommand.MergeMyResults(PipelineResultTypes.Information, PipelineResultTypes.Output); + if (psCommand.Commands.Count > 0) + { + // We need to do merge errors and output before rendering with an Out- cmdlet + Command lastCommand = psCommand.Commands[psCommand.Commands.Count - 1]; + lastCommand.MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output); + lastCommand.MergeMyResults(PipelineResultTypes.Information, PipelineResultTypes.Output); + } return psCommand; } diff --git a/test/PowerShellEditorServices.Test.Shared/TestUtilities/TestUtilities.cs b/test/PowerShellEditorServices.Test.Shared/TestUtilities/TestUtilities.cs index f29c625be..1441b56a6 100644 --- a/test/PowerShellEditorServices.Test.Shared/TestUtilities/TestUtilities.cs +++ b/test/PowerShellEditorServices.Test.Shared/TestUtilities/TestUtilities.cs @@ -36,6 +36,21 @@ public static string NormalizePath(string unixPath) return unixPath; } + /// + /// Gets a normalized path from the directory of this assembly to the given path under the + /// shared test folder. + /// + /// A path or file under the shared test folder. + /// The normalized and resolved path to it. + public static string GetSharedPath(string path) + { + // TODO: When testing net461 with x64 host, another .. is needed! + return NormalizePath(Path.Combine( + Path.GetDirectoryName(typeof(TestUtilities).Assembly.Location), + "../../../../PowerShellEditorServices.Test.Shared", + path)); + } + /// /// Take a string with UNIX newlines and replaces them with platform-appropriate newlines. /// diff --git a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs index 7f3a5dc2e..d36ced933 100644 --- a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs @@ -19,6 +19,7 @@ using Xunit; namespace Microsoft.PowerShell.EditorServices.Test.Debugging { + [Trait("Category", "DebugService")] public class DebugServiceTests : IDisposable { private readonly PsesInternalHost psesHost; @@ -81,13 +82,7 @@ private void OnDebuggerStopped(object sender, DebuggerStoppedEventArgs e) private ScriptFile GetDebugScript(string fileName) { - return workspace.GetFile( - TestUtilities.NormalizePath(Path.Combine( - Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location), - // TODO: When testing net461 with x64 host, another .. is needed! - "../../../../PowerShellEditorServices.Test.Shared/Debugging", - fileName - ))); + return workspace.GetFile(TestUtilities.GetSharedPath(Path.Combine("Debugging", fileName))); } private VariableDetailsBase[] GetVariables(string scopeName) @@ -147,7 +142,6 @@ private Task> GetConfirmedBreakpoints(ScriptFile s CancellationToken.None); } - [Trait("Category", "DebugService")] [Fact] // This regression test asserts that `ExecuteScriptWithArgsAsync` works for both script // files and, in this case, in-line scripts (commands). The bug was that the cwd was @@ -176,7 +170,6 @@ await debugService.SetCommandBreakpointsAsync( Assert.Equal("[ArrayList: 0]", var.ValueString); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerAcceptsScriptArgs() { @@ -238,7 +231,6 @@ public async Task DebuggerAcceptsScriptArgs() Assert.Equal("\"Extra1\"", childVars[0].ValueString); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerSetsAndClearsFunctionBreakpoints() { @@ -264,7 +256,6 @@ public async Task DebuggerSetsAndClearsFunctionBreakpoints() Assert.Empty(breakpoints); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerStopsOnFunctionBreakpoints() { @@ -295,7 +286,6 @@ public async Task DebuggerStopsOnFunctionBreakpoints() Assert.Equal("2", i.ValueString); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerSetsAndClearsLineBreakpoints() { @@ -329,7 +319,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Empty(remainingBreakpoints); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerStopsOnLineBreakpoints() { @@ -346,7 +335,6 @@ await debugService.SetLineBreakpointsAsync( AssertDebuggerStopped(debugScriptFile.FilePath, 7); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerStopsOnConditionalBreakpoints() { @@ -384,7 +372,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Equal($"{breakpointValue2}", i.ValueString); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerStopsOnHitConditionBreakpoint() { @@ -408,7 +395,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Equal($"{hitCount}", i.ValueString); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerStopsOnConditionalAndHitConditionBreakpoint() { @@ -431,7 +417,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Equal("10", i.ValueString); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerProvidesMessageForInvalidConditionalBreakpoint() { @@ -460,7 +445,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Contains("Unexpected token '-ez'", breakpoints[0].Message); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerFindsParseableButInvalidSimpleBreakpointConditions() { @@ -483,7 +467,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Contains("Use '-gt' instead of '>'", breakpoints[1].Message); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerBreaksWhenRequested() { @@ -495,7 +478,6 @@ public async Task DebuggerBreaksWhenRequested() AssertDebuggerPaused(); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerRunsCommandsWhileStopped() { @@ -510,7 +492,6 @@ public async Task DebuggerRunsCommandsWhileStopped() Assert.Equal(17, (await executeTask.ConfigureAwait(true))[0]); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerVariableStringDisplaysCorrectly() { @@ -529,7 +510,6 @@ await debugService.SetLineBreakpointsAsync( Assert.False(var.IsExpandable); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerGetsVariables() { @@ -579,7 +559,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Equal("$false", falseVar.ValueString); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerSetsVariablesNoConversion() { @@ -634,7 +613,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Equal(newGlobalIntValue, intGlobalVar.ValueString); } - [Trait("Category", "DebugService")] [Fact(Skip = "Variable conversion is broken")] public async Task DebuggerSetsVariablesWithConversion() { @@ -693,7 +671,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Equal(newGlobalValue, globalVar.ValueString); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerVariableEnumDisplaysCorrectly() { @@ -714,7 +691,6 @@ await debugService.SetLineBreakpointsAsync( Assert.False(var.IsExpandable); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerVariableHashtableDisplaysCorrectly() { @@ -751,7 +727,6 @@ await debugService.SetLineBreakpointsAsync( } } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerVariableNullStringDisplaysCorrectly() { @@ -772,7 +747,6 @@ await debugService.SetLineBreakpointsAsync( Assert.True(nullStringVar.IsExpandable); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerVariablePSObjectDisplaysCorrectly() { @@ -800,7 +774,6 @@ await debugService.SetLineBreakpointsAsync( Assert.Equal("\"John\"", childVars["Name"]); } - [Trait("Category", "DebugService")] [Fact] public async Task DebuggerVariablePSCustomObjectDisplaysCorrectly() { @@ -830,7 +803,6 @@ await debugService.SetLineBreakpointsAsync( // Verifies fix for issue #86, $proc = Get-Process foo displays just the ETS property set // and not all process properties. - [Trait("Category", "DebugService")] [Fact(Skip = "Length of child vars is wrong now")] public async Task DebuggerVariableProcessObjDisplaysCorrectly() { diff --git a/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs b/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs deleted file mode 100644 index d65a186ac..000000000 --- a/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Management.Automation; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.PowerShell.EditorServices.Services; -using Microsoft.PowerShell.EditorServices.Test.Shared; -using Microsoft.PowerShell.EditorServices.Utility; -using Xunit; - -namespace Microsoft.PowerShell.EditorServices.Test.Console -{ - /* - public class PowerShellContextTests : IDisposable - { - // Borrowed from `VersionUtils` which can't be used here due to an initialization problem. - private static bool IsWindows { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - - private PowerShellContextService powerShellContext; - private AsyncQueue stateChangeQueue; - - private static readonly string s_debugTestFilePath = - TestUtilities.NormalizePath("../../../../PowerShellEditorServices.Test.Shared/Debugging/DebugTest.ps1"); - - public PowerShellContextTests() - { - this.powerShellContext = PowerShellContextFactory.Create(NullLogger.Instance); - this.powerShellContext.SessionStateChanged += OnSessionStateChanged; - this.stateChangeQueue = new AsyncQueue(); - } - - public void Dispose() - { - this.powerShellContext.Close(); - this.powerShellContext = null; - } - - [Trait("Category", "PowerShellContext")] - [Fact] - public async Task CanExecutePSCommand() - { - PSCommand psCommand = new PSCommand(); - psCommand.AddScript("$a = \"foo\"; $a"); - - var executeTask = - this.powerShellContext.ExecuteCommandAsync(psCommand); - - await this.AssertStateChange(PowerShellContextState.Running).ConfigureAwait(false); - await this.AssertStateChange(PowerShellContextState.Ready).ConfigureAwait(false); - - var result = await executeTask.ConfigureAwait(false); - Assert.Equal("foo", result.First()); - } - - [Trait("Category", "PowerShellContext")] - [Fact] - public async Task CanQueueParallelRunspaceRequests() - { - // Concurrently initiate 4 requests in the session - Task taskOne = this.powerShellContext.ExecuteScriptStringAsync("$x = 100"); - Task handleTask = this.powerShellContext.GetRunspaceHandleAsync(); - Task taskTwo = this.powerShellContext.ExecuteScriptStringAsync("$x += 200"); - Task taskThree = this.powerShellContext.ExecuteScriptStringAsync("$x = $x / 100"); - - PSCommand psCommand = new PSCommand(); - psCommand.AddScript("$x"); - Task> resultTask = this.powerShellContext.ExecuteCommandAsync(psCommand); - - // Wait for the requested runspace handle and then dispose it - RunspaceHandle handle = await handleTask.ConfigureAwait(false); - handle.Dispose(); - - // Wait for all of the executes to complete - await Task.WhenAll(taskOne, taskTwo, taskThree, resultTask).ConfigureAwait(false); - - // At this point, the remaining command executions should execute and complete - int result = resultTask.Result.FirstOrDefault(); - - // 100 + 200 = 300, then divided by 100 is 3. We are ensuring that - // the commands were executed in the sequence they were called. - Assert.Equal(3, result); - } - - [Trait("Category", "PowerShellContext")] - [Fact] - public async Task CanAbortExecution() - { - var executeTask = - Task.Run( - async () => - { - var unusedTask = this.powerShellContext.ExecuteScriptWithArgsAsync(s_debugTestFilePath); - await Task.Delay(50).ConfigureAwait(false); - this.powerShellContext.AbortExecution(); - }); - - await this.AssertStateChange(PowerShellContextState.Running).ConfigureAwait(false); - await this.AssertStateChange(PowerShellContextState.Aborting).ConfigureAwait(false); - await this.AssertStateChange(PowerShellContextState.Ready).ConfigureAwait(false); - - await executeTask.ConfigureAwait(false); - } - - [Trait("Category", "PowerShellContext")] - [Fact] - public async Task CanResolveAndLoadProfilesForHostId() - { - string[] expectedProfilePaths = - new string[] - { - PowerShellContextFactory.TestProfilePaths.AllUsersAllHosts, - PowerShellContextFactory.TestProfilePaths.AllUsersCurrentHost, - PowerShellContextFactory.TestProfilePaths.CurrentUserAllHosts, - PowerShellContextFactory.TestProfilePaths.CurrentUserCurrentHost - }; - - // Load the profiles for the test host name - await this.powerShellContext.LoadHostProfilesAsync().ConfigureAwait(false); - - // Ensure that all the paths are set in the correct variables - // and that the current user's host profile got loaded - PSCommand psCommand = new PSCommand(); - psCommand.AddScript( - "\"$($profile.AllUsersAllHosts) " + - "$($profile.AllUsersCurrentHost) " + - "$($profile.CurrentUserAllHosts) " + - "$($profile.CurrentUserCurrentHost) " + - "$(Assert-ProfileLoaded)\""); - - var result = - await this.powerShellContext.ExecuteCommandAsync( - psCommand).ConfigureAwait(false); - - string expectedString = - string.Format( - "{0} True", - string.Join( - " ", - expectedProfilePaths)); - - Assert.Equal(expectedString, result.FirstOrDefault(), true); - } - - [Trait("Category", "PSReadLine")] - [Fact] - public void CanGetPSReadLineProxy() - { - Assert.True(PSReadLinePromptContext.TryGetPSReadLineProxy( - NullLogger.Instance, - PowerShellContextFactory.InitialRunspace, - PowerShellContextFactory.BundledModulePath, - out PSReadLineProxy proxy)); - } - - #region Helper Methods - - private async Task AssertStateChange(PowerShellContextState expectedState) - { - SessionStateChangedEventArgs newState = - await this.stateChangeQueue.DequeueAsync().ConfigureAwait(false); - - Assert.Equal(expectedState, newState.NewSessionState); - } - - private void OnSessionStateChanged(object sender, SessionStateChangedEventArgs e) - { - this.stateChangeQueue.EnqueueAsync(e).Wait(); - } - - #endregion - } - */ -} diff --git a/test/PowerShellEditorServices.Test/Session/PsesInternalHostTests.cs b/test/PowerShellEditorServices.Test/Session/PsesInternalHostTests.cs new file mode 100644 index 000000000..87ef20bf1 --- /dev/null +++ b/test/PowerShellEditorServices.Test/Session/PsesInternalHostTests.cs @@ -0,0 +1,162 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.PowerShell.EditorServices.Services.PowerShell.Console; +using Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution; +using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host; +using Xunit; + +namespace Microsoft.PowerShell.EditorServices.Test.Console +{ + using System.Management.Automation; + using System.Management.Automation.Runspaces; + + [Trait("Category", "PsesInternalHost")] + public class PsesInternalHostTests : IDisposable + { + private readonly PsesInternalHost psesHost; + + public PsesInternalHostTests() + { + psesHost = PsesHostFactory.Create(NullLoggerFactory.Instance); + } + + public void Dispose() + { + psesHost.StopAsync().Wait(); + GC.SuppressFinalize(this); + } + + [Fact] + public async Task CanExecutePSCommand() + { + Assert.True(psesHost.IsRunning); + var command = new PSCommand().AddScript("$a = \"foo\"; $a"); + var task = psesHost.ExecutePSCommandAsync(command, CancellationToken.None); + var result = await task.ConfigureAwait(true); + Assert.Equal("foo", result[0]); + } + + [Fact] // https://github.com/PowerShell/vscode-powershell/issues/3677 + public async Task CanHandleThrow() + { + await psesHost.ExecutePSCommandAsync( + new PSCommand().AddScript("throw"), + CancellationToken.None, + new PowerShellExecutionOptions { ThrowOnError = false }).ConfigureAwait(true); + } + + [Fact] + public async Task CanQueueParallelPSCommands() + { + // Concurrently initiate 4 requests in the session. + Task taskOne = psesHost.ExecutePSCommandAsync( + new PSCommand().AddScript("$x = 100"), + CancellationToken.None); + + Task taskTwo = psesHost.ExecutePSCommandAsync( + new PSCommand().AddScript("$x += 200"), + CancellationToken.None); + + Task taskThree = psesHost.ExecutePSCommandAsync( + new PSCommand().AddScript("$x = $x / 100"), + CancellationToken.None); + + Task> resultTask = psesHost.ExecutePSCommandAsync( + new PSCommand().AddScript("$x"), + CancellationToken.None); + + // Wait for all of the executes to complete. + await Task.WhenAll(taskOne, taskTwo, taskThree, resultTask).ConfigureAwait(true); + + // Sanity checks + Assert.Equal(RunspaceState.Opened, psesHost.Runspace.RunspaceStateInfo.State); + + // 100 + 200 = 300, then divided by 100 is 3. We are ensuring that + // the commands were executed in the sequence they were called. + Assert.Equal(3, (await resultTask.ConfigureAwait(true))[0]); + } + + [Fact] + public async Task CanCancelExecutionWithToken() + { + _ = await Assert.ThrowsAsync(() => + { + return psesHost.ExecutePSCommandAsync( + new PSCommand().AddScript("Start-Sleep 10"), + new CancellationTokenSource(1000).Token); + }).ConfigureAwait(true); + } + + [Fact] + public async Task CanCancelExecutionWithMethod() + { + var executeTask = psesHost.ExecutePSCommandAsync( + new PSCommand().AddScript("Start-Sleep 10"), + CancellationToken.None); + + // Wait until our task has started. + Thread.Sleep(2000); + psesHost.CancelCurrentTask(); + _ = await Assert.ThrowsAsync(() => executeTask).ConfigureAwait(true); + Assert.True(executeTask.IsCanceled); + } + + [Fact] + public async Task CanResolveAndLoadProfilesForHostId() + { + string[] expectedProfilePaths = + new string[] + { + PsesHostFactory.TestProfilePaths.AllUsersAllHosts, + PsesHostFactory.TestProfilePaths.AllUsersCurrentHost, + PsesHostFactory.TestProfilePaths.CurrentUserAllHosts, + PsesHostFactory.TestProfilePaths.CurrentUserCurrentHost + }; + + // Load the profiles for the test host name + await psesHost.LoadHostProfilesAsync(CancellationToken.None).ConfigureAwait(true); + + // Ensure that all the paths are set in the correct variables + // and that the current user's host profile got loaded + PSCommand psCommand = new PSCommand().AddScript( + "\"$($profile.AllUsersAllHosts) " + + "$($profile.AllUsersCurrentHost) " + + "$($profile.CurrentUserAllHosts) " + + "$($profile.CurrentUserCurrentHost) " + + "$(Assert-ProfileLoaded)\""); + + var result = await psesHost.ExecutePSCommandAsync(psCommand, CancellationToken.None).ConfigureAwait(true); + + string expectedString = + string.Format( + "{0} True", + string.Join( + " ", + expectedProfilePaths)); + + Assert.Equal(expectedString, result[0], ignoreCase: true); + } + + [Fact] + public async Task CanLoadPSReadLine() + { + // NOTE: This is slightly more complicated than one would expect because we explicitly + // need it to run on the pipeline thread otherwise Windows complains about the the + // thread's appartment state not matching. + Assert.True(await psesHost.ExecuteDelegateAsync( + nameof(psesHost.TryLoadPSReadLine), + executionOptions: null, + (pwsh, _) => psesHost.TryLoadPSReadLine( + pwsh, + (EngineIntrinsics)pwsh.Runspace.SessionStateProxy.GetVariable("ExecutionContext"), + out IReadLine readLine), + CancellationToken.None).ConfigureAwait(true)); + } + } +}