From 03bca8dfb592035af67cdf1804994a63e8867269 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 28 Apr 2020 10:14:45 -0700 Subject: [PATCH] Support ConstrainedLanguage mode (#1269) * change some to AddScript useLocalScope * initial support of constrainedlanguage mode * polish ConstrainedLanguage mode * useLocalScope * have e2e tests also run in CLM Co-authored-by: Tyler Leonhardt (POWERSHELL) --- PowerShellEditorServices.build.ps1 | 10 ++++ .../Commands/Public/Clear-Host.ps1 | 4 +- .../Commands/StartEditorServicesCommand.cs | 2 + .../Configuration/EditorServicesConfig.cs | 7 +++ .../EditorServicesLoader.cs | 17 +----- .../Internal/EditorServicesRunner.cs | 1 + .../Hosting/HostStartupInfo.cs | 10 ++++ .../PowerShellContextService.cs | 32 ++++++++---- .../Capabilities/DscBreakpointCapability.cs | 13 +++-- .../Session/ExecutionOptions.cs | 12 +++++ .../Session/PSReadLinePromptContext.cs | 2 +- .../Session/PowerShellVersionDetails.cs | 4 +- .../Session/RunspaceDetails.cs | 3 +- .../Session/SessionDetails.cs | 3 +- .../LanguageServerProtocolMessageTests.cs | 52 +++++++++++++++---- .../PowerShellEditorServices.Test.E2E.csproj | 1 + .../TestsFixture.cs | 7 +-- .../PowerShellContextFactory.cs | 2 + 18 files changed, 132 insertions(+), 50 deletions(-) diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index af68856eb..66a17c569 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -274,6 +274,16 @@ task TestE2E { $env:PWSH_EXE_NAME = if ($IsCoreCLR) { "pwsh" } else { "powershell" } exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Core (DotNetTestFilter) } + + # Run E2E tests in ConstrainedLanguage mode. + if (!$script:IsUnix) { + try { + [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", [System.EnvironmentVariableTarget]::Machine); + exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Core (DotNetTestFilter) } + } finally { + [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", $null, [System.EnvironmentVariableTarget]::Machine); + } + } } task LayoutModule -After Build { diff --git a/module/PowerShellEditorServices/Commands/Public/Clear-Host.ps1 b/module/PowerShellEditorServices/Commands/Public/Clear-Host.ps1 index 50e9d4503..373f19d69 100644 --- a/module/PowerShellEditorServices/Commands/Public/Clear-Host.ps1 +++ b/module/PowerShellEditorServices/Commands/Public/Clear-Host.ps1 @@ -10,7 +10,9 @@ function Clear-Host { param() __clearhost - $psEditor.Window.Terminal.Clear() + if ($host.Runspace.LanguageMode -eq [System.Management.Automation.PSLanguageMode]::FullLanguage) { + $psEditor.Window.Terminal.Clear() + } } if (!$IsMacOS -or $IsLinux) { diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index 3eebe047c..9c24da69f 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -11,6 +11,7 @@ using System.Management.Automation; using System.Reflection; using SMA = System.Management.Automation; +using System.Management.Automation.Runspaces; using Microsoft.PowerShell.EditorServices.Hosting; using System.Globalization; using System.Collections; @@ -358,6 +359,7 @@ private EditorServicesConfig CreateConfigObject() AdditionalModules = AdditionalModules, LanguageServiceTransport = GetLanguageServiceTransport(), DebugServiceTransport = GetDebugServiceTransport(), + LanguageMode = Runspace.DefaultRunspace.SessionStateProxy.LanguageMode, ProfilePaths = new ProfilePathConfig { AllUsersAllHosts = GetProfilePathFromProfileObject(profile, ProfileUserKind.AllUsers, ProfileHostKind.AllHosts), diff --git a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs index e56f4d27b..7650a522b 100644 --- a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs +++ b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs @@ -4,6 +4,7 @@ // using System.Collections.Generic; +using System.Management.Automation; using System.Management.Automation.Host; namespace Microsoft.PowerShell.EditorServices.Hosting @@ -111,6 +112,12 @@ public EditorServicesConfig( /// public ProfilePathConfig ProfilePaths { get; set; } + /// + /// The language mode inherited from the orginal PowerShell process. + /// This will be used when creating runspaces so that we honor the same language mode. + /// + public PSLanguageMode LanguageMode { get; internal set; } + public string StartupBanner { get; set; } = @" =====> PowerShell Integrated Console <===== diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs index 7690070a0..f387063e5 100644 --- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs +++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs @@ -190,8 +190,6 @@ public Task LoadAndRunEditorServicesAsync() // Make sure the .NET Framework version supports .NET Standard 2.0 CheckNetFxVersion(); #endif - // Ensure the language mode allows us to run - CheckLanguageMode(); // Add the bundled modules to the PSModulePath UpdatePSModulePath(); @@ -250,19 +248,6 @@ private void CheckNetFxVersion() } #endif - /// - /// PSES currently does not work in Constrained Language Mode, because PSReadLine script invocations won't work in it. - /// Ideally we can find a better way so that PSES will work in CLM. - /// - private void CheckLanguageMode() - { - _logger.Log(PsesLogLevel.Diagnostic, "Checking that PSES is running in FullLanguage mode"); - if (Runspace.DefaultRunspace.SessionStateProxy.LanguageMode != PSLanguageMode.FullLanguage) - { - throw new InvalidOperationException("Cannot start PowerShell Editor Services in Constrained Language Mode"); - } - } - private void UpdatePSModulePath() { if (string.IsNullOrEmpty(_hostConfig.BundledModulePath)) @@ -332,7 +317,7 @@ private string GetPSOutputEncoding() { using (var pwsh = SMA.PowerShell.Create()) { - return pwsh.AddScript("$OutputEncoding.EncodingName").Invoke()[0]; + return pwsh.AddScript("$OutputEncoding.EncodingName", useLocalScope: true).Invoke()[0]; } } diff --git a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs index cd8ae8013..730964127 100644 --- a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs +++ b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs @@ -237,6 +237,7 @@ private HostStartupInfo CreateHostStartupInfo() profilePaths, _config.FeatureFlags, _config.AdditionalModules, + _config.LanguageMode, _config.LogPath, (int)_config.LogLevel, consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None, diff --git a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs index b6ff618a3..5cd5232f9 100644 --- a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs +++ b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Management.Automation; using System.Management.Automation.Host; namespace Microsoft.PowerShell.EditorServices.Hosting @@ -89,6 +90,12 @@ public sealed class HostStartupInfo /// public string LogPath { get; } + /// + /// The language mode inherited from the orginal PowerShell process. + /// This will be used when creating runspaces so that we honor the same language mode. + /// + public PSLanguageMode LanguageMode { get; } + /// /// The minimum log level of log events to be logged. /// @@ -117,6 +124,7 @@ public sealed class HostStartupInfo /// The path to the user specific profile. /// Flags of features to enable. /// Names or paths of additional modules to import. + /// The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same language mode. /// The path to log to. /// The minimum log event level. /// Enable console if true. @@ -129,6 +137,7 @@ public HostStartupInfo( ProfilePathInfo profilePaths, IReadOnlyList featureFlags, IReadOnlyList additionalModules, + PSLanguageMode languageMode, string logPath, int logLevel, bool consoleReplEnabled, @@ -141,6 +150,7 @@ public HostStartupInfo( ProfilePaths = profilePaths; FeatureFlags = featureFlags ?? Array.Empty(); AdditionalModules = additionalModules ?? Array.Empty(); + LanguageMode = languageMode; LogPath = logPath; LogLevel = logLevel; ConsoleReplEnabled = consoleReplEnabled; diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 4f9639209..f79cbc4c2 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -213,7 +213,7 @@ public static PowerShellContextService Create( hostUserInterface, logger); - Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost); + Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.LanguageMode); powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); powerShellContext.ImportCommandsModuleAsync(); @@ -244,9 +244,7 @@ public static PowerShellContextService Create( /// /// /// - /// - /// The EditorServicesPSHostUserInterface to use for this instance. - /// + /// The EditorServicesPSHostUserInterface to use for this instance. /// An ILogger implementation to use for this instance. /// public static Runspace CreateRunspace( @@ -260,15 +258,16 @@ public static Runspace CreateRunspace( var psHost = new EditorServicesPSHost(powerShellContext, hostDetails, hostUserInterface, logger); powerShellContext.ConsoleWriter = hostUserInterface; powerShellContext.ConsoleReader = hostUserInterface; - return CreateRunspace(psHost); + return CreateRunspace(psHost, hostDetails.LanguageMode); } /// /// /// - /// + /// The PSHost that will be used for this Runspace. + /// The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same language mode. /// - public static Runspace CreateRunspace(PSHost psHost) + public static Runspace CreateRunspace(PSHost psHost, PSLanguageMode languageMode) { InitialSessionState initialSessionState; if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") { @@ -277,6 +276,11 @@ public static Runspace CreateRunspace(PSHost psHost) initialSessionState = InitialSessionState.CreateDefault2(); } + // Create and initialize a new Runspace while honoring the LanguageMode of the original runspace + // that started PowerShell Editor Services. This is because the PowerShell Integrated Console + // should have the same LanguageMode of whatever is set by the system. + initialSessionState.LanguageMode = languageMode; + Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); // Windows PowerShell must be hosted in STA mode @@ -410,6 +414,8 @@ public void Initialize( if (powerShellVersion.Major >= 5 && this.isPSReadLineEnabled && + // TODO: Figure out why PSReadLine isn't working in ConstrainedLanguage mode. + initialRunspace.SessionStateProxy.LanguageMode == PSLanguageMode.FullLanguage && PSReadLinePromptContext.TryGetPSReadLineProxy(logger, initialRunspace, out PSReadLineProxy proxy)) { this.PromptContext = new PSReadLinePromptContext( @@ -597,7 +603,7 @@ public async Task> ExecuteCommandAsync( // cancelled prompt when it's called again. if (executionOptions.AddToHistory) { - this.PromptContext.AddToHistory(psCommand.Commands[0].CommandText); + this.PromptContext.AddToHistory(executionOptions.InputString ?? psCommand.Commands[0].CommandText); } bool hadErrors = false; @@ -686,7 +692,7 @@ public async Task> ExecuteCommandAsync( if (executionOptions.WriteInputToHost) { this.WriteOutput( - psCommand.Commands[0].CommandText, + executionOptions.InputString ?? psCommand.Commands[0].CommandText, includeNewLine: true); } @@ -1156,12 +1162,16 @@ internal async Task InvokeReadLineAsync(bool isCommandLine, Cancellation cancellationToken).ConfigureAwait(false); } - internal static TResult ExecuteScriptAndGetItem(string scriptToExecute, Runspace runspace, TResult defaultValue = default) + internal static TResult ExecuteScriptAndGetItem( + string scriptToExecute, + Runspace runspace, + TResult defaultValue = default, + bool useLocalScope = false) { using (PowerShell pwsh = PowerShell.Create()) { pwsh.Runspace = runspace; - IEnumerable results = pwsh.AddScript(scriptToExecute).Invoke(); + IEnumerable results = pwsh.AddScript(scriptToExecute, useLocalScope).Invoke(); return results.DefaultIfEmpty(defaultValue).First(); } } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/Capabilities/DscBreakpointCapability.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/Capabilities/DscBreakpointCapability.cs index 247c1d13e..4c9c87d92 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/Capabilities/DscBreakpointCapability.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/Capabilities/DscBreakpointCapability.cs @@ -121,14 +121,17 @@ public static DscBreakpointCapability CheckForCapability( runspaceDetails.AddCapability(capability); powerShell.Commands.Clear(); - powerShell.AddScript("Write-Host \"Gathering DSC resource paths, this may take a while...\""); - powerShell.Invoke(); + powerShell + .AddCommand("Microsoft.PowerShell.Utility\\Write-Host") + .AddArgument("Gathering DSC resource paths, this may take a while...") + .Invoke(); // Get the list of DSC resource paths powerShell.Commands.Clear(); - powerShell.AddCommand("Get-DscResource"); - powerShell.AddCommand("Select-Object"); - powerShell.AddParameter("ExpandProperty", "ParentPath"); + powerShell + .AddCommand("Get-DscResource") + .AddCommand("Select-Object") + .AddParameter("ExpandProperty", "ParentPath"); Collection resourcePaths = null; diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/ExecutionOptions.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/ExecutionOptions.cs index 31e0ab1de..df585ca79 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/ExecutionOptions.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/ExecutionOptions.cs @@ -46,6 +46,18 @@ internal class ExecutionOptions /// public bool WriteInputToHost { get; set; } + /// + /// If this is set, we will use this string for history and writing to the host + /// instead of grabbing the command from the PSCommand. + /// + public string InputString { get; set; } + + /// + /// If this is set, we will use this string for history and writing to the host + /// instead of grabbing the command from the PSCommand. + /// + public bool UseNewScope { get; set; } + /// /// Gets or sets a value indicating whether the command to /// be executed is a console input prompt, such as the diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs index 93a098f2e..7a14d8e7a 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs @@ -91,7 +91,7 @@ internal static bool TryGetPSReadLineProxy( { pwsh.Runspace = runspace; var psReadLineType = pwsh - .AddScript(ReadLineInitScript) + .AddScript(ReadLineInitScript, useLocalScope: true) .Invoke() .FirstOrDefault(); diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PowerShellVersionDetails.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PowerShellVersionDetails.cs index 72b8dc5be..71d56f234 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PowerShellVersionDetails.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PowerShellVersionDetails.cs @@ -101,7 +101,7 @@ public static PowerShellVersionDetails GetVersionDetails(Runspace runspace, ILog try { - var psVersionTable = PowerShellContextService.ExecuteScriptAndGetItem("$PSVersionTable", runspace); + var psVersionTable = PowerShellContextService.ExecuteScriptAndGetItem("$PSVersionTable", runspace, useLocalScope: true); if (psVersionTable != null) { var edition = psVersionTable["PSEdition"] as string; @@ -134,7 +134,7 @@ public static PowerShellVersionDetails GetVersionDetails(Runspace runspace, ILog versionString = powerShellVersion.ToString(); } - var arch = PowerShellContextService.ExecuteScriptAndGetItem("$env:PROCESSOR_ARCHITECTURE", runspace); + var arch = PowerShellContextService.ExecuteScriptAndGetItem("$env:PROCESSOR_ARCHITECTURE", runspace, useLocalScope: true); if (arch != null) { if (string.Equals(arch, "AMD64", StringComparison.CurrentCultureIgnoreCase)) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/RunspaceDetails.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/RunspaceDetails.cs index d5013c9f9..be5aea9cf 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/RunspaceDetails.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/RunspaceDetails.cs @@ -223,7 +223,8 @@ internal static RunspaceDetails CreateFromRunspace( PowerShellContextService.ExecuteScriptAndGetItem( "$Host.Name", runspace, - defaultValue: string.Empty); + defaultValue: string.Empty, + useLocalScope: true); // hostname is 'ServerRemoteHost' when the user enters a session. // ex. Enter-PSSession diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/SessionDetails.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/SessionDetails.cs index 9054e5784..39f12fdae 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/SessionDetails.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/SessionDetails.cs @@ -56,7 +56,8 @@ public static PSCommand GetDetailsCommand() { PSCommand infoCommand = new PSCommand(); infoCommand.AddScript( - "@{ 'computerName' = if ([Environment]::MachineName) {[Environment]::MachineName} else {'localhost'}; 'processId' = $PID; 'instanceId' = $host.InstanceId }"); + "@{ 'computerName' = if ([Environment]::MachineName) {[Environment]::MachineName} else {'localhost'}; 'processId' = $PID; 'instanceId' = $host.InstanceId }", + useLocalScope: true); return infoCommand; } diff --git a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs index 9f5e697d3..79bbee7f2 100644 --- a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs +++ b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs @@ -135,9 +135,13 @@ function CanSendWorkspaceSymbolRequest { Assert.Equal("CanSendWorkspaceSymbolRequest { }", symbol.Name); } - [Fact] + [SkippableFact] public async Task CanReceiveDiagnosticsFromFileOpen() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + NewTestFile("$a = 4"); await WaitForDiagnostics(); @@ -154,9 +158,13 @@ public async Task WontReceiveDiagnosticsFromFileOpenThatIsNotPowerShell() Assert.Empty(Diagnostics); } - [Fact] + [SkippableFact] public async Task CanReceiveDiagnosticsFromFileChanged() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string filePath = NewTestFile("$a = 4"); await WaitForDiagnostics(); Diagnostics.Clear(); @@ -191,9 +199,13 @@ public async Task CanReceiveDiagnosticsFromFileChanged() Assert.Equal("PSUseDeclaredVarsMoreThanAssignments", diagnostic.Code); } - [Fact] + [SkippableFact] public async Task CanReceiveDiagnosticsFromConfigurationChange() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + NewTestFile("gci | % { $_ }"); await WaitForDiagnostics(); @@ -275,9 +287,13 @@ await LanguageClient.SendRequest>( }); } - [Fact] + [SkippableFact] public async Task CanSendFormattingRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string scriptPath = NewTestFile(@" gci | % { Get-Process @@ -306,9 +322,13 @@ public async Task CanSendFormattingRequest() Assert.Contains("\t", textEdit.NewText); } - [Fact] + [SkippableFact] public async Task CanSendRangeFormattingRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string scriptPath = NewTestFile(@" gci | % { Get-Process @@ -756,9 +776,13 @@ function CanSendReferencesCodeLensRequest { Assert.Equal("1 reference", codeLensResolveResult.Command.Title); } - [Fact] + [SkippableFact] public async Task CanSendCodeActionRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string filePath = NewTestFile("gci"); await WaitForDiagnostics(); @@ -929,9 +953,11 @@ await LanguageClient.SendRequest( Assert.Equal(33, locationOrLocationLink.Location.Range.End.Character); } - [Fact] + [SkippableFact] public async Task CanSendGetProjectTemplatesRequest() { + Skip.If(TestsFixture.RunningInConstainedLanguageMode, "Plaster doesn't work in ConstrainedLanguage mode."); + GetProjectTemplatesResponse getProjectTemplatesResponse = await LanguageClient.SendRequest( "powerShell/getProjectTemplates", @@ -951,9 +977,13 @@ await LanguageClient.SendRequest( }); } - [Fact] + [SkippableFact] public async Task CanSendGetCommentHelpRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string scriptPath = NewTestFile(@" function CanSendGetCommentHelpRequest { param( @@ -1012,9 +1042,13 @@ public async Task CanSendGetCommandRequest() Assert.True(pSCommandMessages.Count > 20); } - [Fact] + [SkippableFact] public async Task CanSendExpandAliasRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode, + "This feature currently doesn't support ConstrainedLanguage Mode."); + ExpandAliasResult expandAliasResult = await LanguageClient.SendRequest( "powerShell/expandAlias", diff --git a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj index 58da8923b..5e9dc7ecd 100644 --- a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj +++ b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj @@ -13,6 +13,7 @@ + diff --git a/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs b/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs index e56d4668f..b0eca7af9 100644 --- a/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs +++ b/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs @@ -5,10 +5,7 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Linq; -using OmniSharp.Extensions.LanguageServer.Client; using OmniSharp.Extensions.LanguageServer.Client.Processes; -using OmniSharp.Extensions.LanguageServer.Protocol.Models; using Xunit; namespace PowerShellEditorServices.Test.E2E @@ -42,6 +39,10 @@ public abstract class TestsFixture : IAsyncLifetime public static string PwshExe { get; } = Environment.GetEnvironmentVariable("PWSH_EXE_NAME") ?? "pwsh"; + public static bool IsWindowsPowerShell { get; } = PwshExe.Contains("powershell"); + public static bool RunningInConstainedLanguageMode { get; } = + Environment.GetEnvironmentVariable("__PSLockdownPolicy", EnvironmentVariableTarget.Machine) != null; + public virtual bool IsDebugAdapterTests { get; set; } public async Task InitializeAsync() diff --git a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs index 17d02c5ed..7b5cb229c 100644 --- a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs +++ b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Management.Automation; using System.Threading; using System.Threading.Tasks; @@ -45,6 +46,7 @@ public static PowerShellContextService Create(ILogger logger) TestProfilePaths, new List(), new List(), + PSLanguageMode.FullLanguage, null, 0, consoleReplEnabled: false,