From 366210e5b6a24ae10d10ff0ffc26501ab53f7083 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 16 Mar 2021 11:21:09 -0700 Subject: [PATCH 1/6] Delete dead `Test.Host` code One sunny day we will salvage this code to create proper tests for the DAP, etc., but for now this code has been dead over a year and wasted developer time (re)determinig so, as the solution still references it and thus the code is analyzed and presents lots of problems. --- PowerShellEditorServices.build.ps1 | 14 +- PowerShellEditorServices.sln | 21 - .../App.config | 6 - .../AssemblyInfo.cs | 9 - .../AttachHelper.cs | 117 -- .../DebugAdapterTests.cs | 142 --- .../LanguageServerTests.cs | 1003 ----------------- .../OutputReader.cs | 139 --- .../PowerShellEditorServices.Test.Host.csproj | 33 - .../ServerTestsBase.cs | 316 ------ .../TestFiles/ChildModule/ChildModule.psm1 | 2 - .../TestFiles/CompleteFunctionName.ps1 | 9 - .../TestFiles/FindReferences.ps1 | 19 - .../TestFiles/Folder With Spaces/.gitkeep | 0 .../TestFiles/Module.psm1 | 1 - .../TestFiles/MultiLineReplace.ps1 | 3 - .../TestFiles/SimpleSemanticError.ps1 | 3 - .../TestFiles/SimpleSyntaxError.ps1 | 3 - .../TestFiles/VariableDefinition.ps1 | 1 - .../xunit.runner.json | 4 - 20 files changed, 1 insertion(+), 1844 deletions(-) delete mode 100644 test/PowerShellEditorServices.Test.Host/App.config delete mode 100644 test/PowerShellEditorServices.Test.Host/AssemblyInfo.cs delete mode 100644 test/PowerShellEditorServices.Test.Host/AttachHelper.cs delete mode 100644 test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs delete mode 100644 test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs delete mode 100644 test/PowerShellEditorServices.Test.Host/OutputReader.cs delete mode 100644 test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj delete mode 100644 test/PowerShellEditorServices.Test.Host/ServerTestsBase.cs delete mode 100644 test/PowerShellEditorServices.Test.Host/TestFiles/ChildModule/ChildModule.psm1 delete mode 100644 test/PowerShellEditorServices.Test.Host/TestFiles/CompleteFunctionName.ps1 delete mode 100644 test/PowerShellEditorServices.Test.Host/TestFiles/FindReferences.ps1 delete mode 100644 test/PowerShellEditorServices.Test.Host/TestFiles/Folder With Spaces/.gitkeep delete mode 100644 test/PowerShellEditorServices.Test.Host/TestFiles/Module.psm1 delete mode 100644 test/PowerShellEditorServices.Test.Host/TestFiles/MultiLineReplace.ps1 delete mode 100644 test/PowerShellEditorServices.Test.Host/TestFiles/SimpleSemanticError.ps1 delete mode 100644 test/PowerShellEditorServices.Test.Host/TestFiles/SimpleSyntaxError.ps1 delete mode 100644 test/PowerShellEditorServices.Test.Host/TestFiles/VariableDefinition.ps1 delete mode 100644 test/PowerShellEditorServices.Test.Host/xunit.runner.json diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index 9d37cbe5e..99b0cd823 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -103,7 +103,7 @@ function Install-Dotnet { Write-Host '.NET installation complete' -ForegroundColor Green } -task SetupDotNet -Before Clean, Build, TestHost, TestServerWinPS, TestServerPS7, TestServerPS71, TestE2E { +task SetupDotNet -Before Clean, Build, TestServerWinPS, TestServerPS7, TestServerPS71, TestE2E { $dotnetPath = "$PSScriptRoot/.dotnet" $dotnetExePath = if ($script:IsUnix) { "$dotnetPath/dotnet" } else { "$dotnetPath/dotnet.exe" } @@ -275,18 +275,6 @@ task TestServerPS71 { } } -task TestHost { - Set-Location .\test\PowerShellEditorServices.Test.Host\ - - if (-not $script:IsUnix) { - exec { & $script:dotnetExe build -f $script:NetRuntime.Desktop } - exec { & $script:dotnetExe test -f $script:NetRuntime.Desktop (DotNetTestFilter) } - } - - exec { & $script:dotnetExe build -c $Configuration -f $script:NetRuntime.PS62 } - exec { & $script:dotnetExe test -f $script:NetRuntime.PS62 (DotNetTestFilter) } -} - task TestE2E { Set-Location .\test\PowerShellEditorServices.Test.E2E\ diff --git a/PowerShellEditorServices.sln b/PowerShellEditorServices.sln index 38106c3a0..0d63a292a 100644 --- a/PowerShellEditorServices.sln +++ b/PowerShellEditorServices.sln @@ -7,8 +7,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F594E7FD-1E7 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{422E561A-8118-4BE7-A54F-9309E4F03AAE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellEditorServices.Test.Host", "test\PowerShellEditorServices.Test.Host\PowerShellEditorServices.Test.Host.csproj", "{3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellEditorServices.Test", "test\PowerShellEditorServices.Test\PowerShellEditorServices.Test.csproj", "{8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellEditorServices.Test.Shared", "test\PowerShellEditorServices.Test.Shared\PowerShellEditorServices.Test.Shared.csproj", "{6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}" @@ -39,24 +37,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.CoreCLR|Any CPU.ActiveCfg = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.CoreCLR|Any CPU.Build.0 = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.CoreCLR|x64.ActiveCfg = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.CoreCLR|x64.Build.0 = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.CoreCLR|x86.ActiveCfg = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.CoreCLR|x86.Build.0 = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Debug|x64.ActiveCfg = Debug|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Debug|x64.Build.0 = Debug|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Debug|x86.ActiveCfg = Debug|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Debug|x86.Build.0 = Debug|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Release|Any CPU.Build.0 = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Release|x64.ActiveCfg = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Release|x64.Build.0 = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Release|x86.ActiveCfg = Release|Any CPU - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028}.Release|x86.Build.0 = Release|Any CPU {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.CoreCLR|Any CPU.ActiveCfg = Release|Any CPU {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.CoreCLR|Any CPU.Build.0 = Release|Any CPU {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.CoreCLR|x64.ActiveCfg = Release|Any CPU @@ -170,7 +150,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {3A5DDD20-5BD0-42F4-89F4-ACC0CE554028} = {422E561A-8118-4BE7-A54F-9309E4F03AAE} {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3} = {422E561A-8118-4BE7-A54F-9309E4F03AAE} {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA} = {422E561A-8118-4BE7-A54F-9309E4F03AAE} {3B38E8DA-8BFF-4264-AF16-47929E6398A3} = {F594E7FD-1E72-4E51-A496-B019C2BA3180} diff --git a/test/PowerShellEditorServices.Test.Host/App.config b/test/PowerShellEditorServices.Test.Host/App.config deleted file mode 100644 index 9735dc735..000000000 --- a/test/PowerShellEditorServices.Test.Host/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/test/PowerShellEditorServices.Test.Host/AssemblyInfo.cs b/test/PowerShellEditorServices.Test.Host/AssemblyInfo.cs deleted file mode 100644 index e3024f5b4..000000000 --- a/test/PowerShellEditorServices.Test.Host/AssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -using Xunit; - -// Disable test parallelization to avoid port reuse issues -[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/test/PowerShellEditorServices.Test.Host/AttachHelper.cs b/test/PowerShellEditorServices.Test.Host/AttachHelper.cs deleted file mode 100644 index 9d1a902bf..000000000 --- a/test/PowerShellEditorServices.Test.Host/AttachHelper.cs +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -// EnvDTE assembly references currently don't seem to be working -// with the new dotnet cli tools, disabling this temporarily. -#if UseEnvDTE - -using EnvDTE; -using System; -using System.Linq; -using System.Runtime.InteropServices; - -namespace Microsoft.PowerShell.EditorServices.Test.Host -{ - internal class AttachHelper - { - public static void AttachToProcessIfDebugging(int processId) - { - if (System.Diagnostics.Debugger.IsAttached) - { - int tryCount = 5; - - while (tryCount-- > 0) - { - try - { - var dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.12.0"); - var processes = dte.Debugger.LocalProcesses.OfType(); - var foundProcess = processes.SingleOrDefault(x => x.ProcessID == processId); - - //EnvDTE.Process foundProcess = null; - //for (int i = 0; i < dte.Debugger.LocalProcesses.Count; i++) - //{ - // foundProcess = dte.Debugger.LocalProcesses.Item(i) as EnvDTE.Process; - - // if (foundProcess != null && foundProcess.ProcessID == processId) - // { - // break; - // } - //} - - if (foundProcess != null) - { - foundProcess.Attach(); - break; - } - else - { - throw new InvalidOperationException("Could not find language service process!"); - } - } - catch (COMException) - { - // Wait a bit and try again - System.Threading.Thread.Sleep(1000); - } - } - } - } - } - - [ComImport, Guid("00000016-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IOleMessageFilter - { - [PreserveSig] - int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo); - - [PreserveSig] - int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType); - - [PreserveSig] - int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType); - } - - public class MessageFilter : IOleMessageFilter - { - private const int Handled = 0, RetryAllowed = 2, Retry = 99, Cancel = -1, WaitAndDispatch = 2; - - int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo) - { - return Handled; - } - - int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType) - { - return dwRejectType == RetryAllowed ? Retry : Cancel; - } - - int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType) - { - return WaitAndDispatch; - } - - public static void Register() - { - CoRegisterMessageFilter(new MessageFilter()); - } - - public static void Revoke() - { - CoRegisterMessageFilter(null); - } - - private static void CoRegisterMessageFilter(IOleMessageFilter newFilter) - { - IOleMessageFilter oldFilter; - CoRegisterMessageFilter(newFilter, out oldFilter); - } - - [DllImport("Ole32.dll")] - private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter); - } -} - -#endif \ No newline at end of file diff --git a/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs b/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs deleted file mode 100644 index 14c6171a6..000000000 --- a/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs +++ /dev/null @@ -1,142 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -using Microsoft.PowerShell.EditorServices.Protocol.Client; -using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter; -using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; -using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel; -using Microsoft.PowerShell.EditorServices.Test.Shared; -using Microsoft.PowerShell.EditorServices.Utility; -using System; -using System.IO; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.PowerShell.EditorServices.Test.Host -{ - public class DebugAdapterTests : ServerTestsBase, IAsyncLifetime - { - private ILogger logger; - private DebugAdapterClient debugAdapterClient; - private string DebugScriptPath = - Path.GetFullPath(TestUtilities.NormalizePath("../../../../PowerShellEditorServices.Test.Shared/Debugging/DebugTest.ps1")); - - public async Task InitializeAsync() - { - string testLogPath = - Path.Combine( - AppContext.BaseDirectory, - "logs", - this.GetType().Name, - Guid.NewGuid().ToString().Substring(0, 8)); - - this.logger = Logging.CreateLogger() - .LogLevel(LogLevel.Verbose) - .AddLogFile(testLogPath + "-client.log") - .Build(); - - testLogPath += "-server.log"; - System.Console.WriteLine(" Output log at path: {0}", testLogPath); - - Tuple pipeNames = - await this.LaunchService( - testLogPath, - waitForDebugger: false); - //waitForDebugger: true); - - this.debugAdapterClient = - new DebugAdapterClient( - await NamedPipeClientChannel.ConnectAsync( - pipeNames.Item2, - MessageProtocolType.DebugAdapter, - this.logger), - this.logger); - - this.messageSender = this.debugAdapterClient; - this.messageHandlers = this.debugAdapterClient; - - await this.debugAdapterClient.StartAsync(); - } - - public Task DisposeAsync() - { - this.debugAdapterClient.Stop(); - this.KillService(); - - return Task.FromResult(true); - } - - [Fact] - public async Task DebugAdapterStopsOnLineBreakpoints() - { - await this.SendRequest( - SetBreakpointsRequest.Type, - new SetBreakpointsRequestArguments - { - Source = new Source - { - Path = DebugScriptPath - }, - Breakpoints = new [] - { - new SourceBreakpoint { Line = 5 }, - new SourceBreakpoint { Line = 7 } - } - }); - - Task breakEventTask = this.WaitForEvent(StoppedEvent.Type); - await this.LaunchScript(DebugScriptPath); - - // Wait for a couple breakpoints - StoppedEventBody stoppedDetails = await breakEventTask; - Assert.Equal(DebugScriptPath, stoppedDetails.Source.Path); - - var stackTraceResponse = - await this.SendRequest( - StackTraceRequest.Type, - new StackTraceRequestArguments()); - - Assert.Equal(5, stackTraceResponse.StackFrames[0].Line); - - breakEventTask = this.WaitForEvent(StoppedEvent.Type); - await this.SendRequest(ContinueRequest.Type, new object()); - stoppedDetails = await breakEventTask; - Assert.Equal(DebugScriptPath, stoppedDetails.Source.Path); - - stackTraceResponse = - await this.SendRequest( - StackTraceRequest.Type, - new StackTraceRequestArguments()); - - Assert.Equal(7, stackTraceResponse.StackFrames[0].Line); - - // Abort script execution - await this.SendRequest(DisconnectRequest.Type, new object()); - } - - [Fact] - public async Task DebugAdapterReceivesOutputEvents() - { - OutputReader outputReader = new OutputReader(this.debugAdapterClient); - - await this.LaunchScript(DebugScriptPath); - - // Skip the first 2 lines which just report the script - // that is being executed - await outputReader.ReadLines(2); - - // Make sure we're getting output from the script - Assert.Equal("Output 1", await outputReader.ReadLine()); - - // Abort script execution - await this.SendRequest(DisconnectRequest.Type, new object()); - } - - private async Task LaunchScript(string scriptPath) - { - await this.debugAdapterClient.LaunchScriptAsync(scriptPath); - } - } -} diff --git a/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs b/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs deleted file mode 100644 index 296d5fd42..000000000 --- a/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs +++ /dev/null @@ -1,1003 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -using Microsoft.PowerShell.EditorServices.Protocol.Client; -using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter; -using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer; -using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; -using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel; -using Microsoft.PowerShell.EditorServices.Protocol.Messages; -using Microsoft.PowerShell.EditorServices.Protocol.Server; -using Microsoft.PowerShell.EditorServices.Session; -using Microsoft.PowerShell.EditorServices.Test.Shared; -using Microsoft.PowerShell.EditorServices.Utility; -using System; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.PowerShell.EditorServices.Test.Host -{ - public class LanguageServerTests : ServerTestsBase, IAsyncLifetime - { - private ILogger logger; - private LanguageServiceClient languageServiceClient; - - public async Task InitializeAsync() - { - string testLogPath = - Path.Combine( - AppContext.BaseDirectory, - "logs", - this.GetType().Name, - Guid.NewGuid().ToString().Substring(0, 8)); - - this.logger = Logging.CreateLogger() - .LogLevel(LogLevel.Verbose) - .AddLogFile(testLogPath + "-client.log") - .Build(); - - testLogPath += "-server.log"; - System.Console.WriteLine(" Output log at path: {0}", testLogPath); - - Tuple pipeNames = - await this.LaunchService( - testLogPath, - waitForDebugger: false); - //waitForDebugger: true); - - this.languageServiceClient = - new LanguageServiceClient( - await NamedPipeClientChannel.ConnectAsync( - pipeNames.Item1, - MessageProtocolType.LanguageServer, - this.logger), - this.logger); - - this.messageSender = this.languageServiceClient; - this.messageHandlers = this.languageServiceClient; - - await this.languageServiceClient.Start(); - } - - public async Task DisposeAsync() - { - await this.languageServiceClient.StopAsync(); - - this.KillService(); - } - - [Fact] - public async Task ServiceReturnsSyntaxErrors() - { - // Send the 'didOpen' event - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/SimpleSyntaxError.ps1"), false); - - // Wait for the diagnostic event - PublishDiagnosticsNotification diagnostics = - await this.WaitForEvent( - PublishDiagnosticsNotification.Type); - - // Was there a syntax error? - Assert.NotEmpty(diagnostics.Diagnostics); - Assert.False( - string.IsNullOrEmpty(diagnostics.Diagnostics[0].Message)); - } - - [Fact] - public async Task ServiceReturnsSemanticMarkers() - { - // Send the 'didOpen' event - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/SimpleSemanticError.ps1"), false); - - // Wait for the diagnostic event - PublishDiagnosticsNotification diagnostics = - await this.WaitForEvent( - PublishDiagnosticsNotification.Type); - - // Was there a semantic error? - Assert.NotEmpty(diagnostics.Diagnostics); - Assert.Contains("unapproved", diagnostics.Diagnostics[0].Message); - } - - [Fact] - public async Task ServiceReturnsNoErrorsForUsingRelativeModulePaths() - { - // Send the 'didOpen' event - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/Module.psm1"), false); - - // Wait for the diagnostic event - PublishDiagnosticsNotification diagnostics = - await this.WaitForEvent( - PublishDiagnosticsNotification.Type); - - // Was there a syntax error? - Assert.Empty(diagnostics.Diagnostics); - } - - [Fact] - public async Task ServiceCompletesFunctionName() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1")); - - CompletionItem[] completions = - await this.SendRequest( - CompletionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1"), - }, - Position = new Position - { - Line = 4, - Character = 3, - } - }); - - Assert.NotNull(completions); - Assert.NotEmpty(completions); - - // TODO: Add more asserts - } - - [Fact] - public async Task CompletesDetailOnVariableSuggestion() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1")); - - CompletionItem[] completions = - await this.SendRequest( - CompletionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1") - }, - Position = new Position - { - Line = 3, - Character = 5 - } - }); - - CompletionItem consoleFileNameItem = - completions - .FirstOrDefault( - c => c.Label == "ConsoleFileName"); - - Assert.NotNull(consoleFileNameItem); - Assert.Equal("[string]", consoleFileNameItem.Detail); - } - - [Fact(Skip = "Skipped until variable documentation gathering is added back.")] - public async Task CompletesDetailOnVariableDocSuggestion() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1")); - - await this.SendRequest( - CompletionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1") - }, - Position = new Position - { - Line = 7, - Character = 5 - } - }); - - // TODO: This section needs to be updated, seems that - // CompletionsResponse is missing. - - //CompletionsResponse completion = this.WaitForMessage(); - //List entryName = new List(); - //entryName.Add("$HKCU:"); - //await this.MessageWriter.WriteMessage( - // new CompletionDetailsRequest - // { - // Arguments = new CompletionDetailsRequestArgs - // { - // File = "TestFiles\\CompleteFunctionName.ps1", - // Line = 7, - // Offset = 5, - // EntryNames = entryName.ToArray() - // } - // }); - //CompletionDetailsResponse completionDetail = this.WaitForMessage(); - //Assert.NotNull(completionDetail.Body[0]); - //Assert.Equal("The software settings for the current user", completionDetail.Body[0].DocString); - } - - [Fact] - public async Task CompletesDetailOnCommandSuggestion() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1")); - - CompletionItem[] completions = - await this.SendRequest( - CompletionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1") - }, - Position = new Position - { - Line = 5, - Character = 8 - } - }); - - CompletionItem completionItem = - completions - .FirstOrDefault( - c => c.Label == "Get-Process"); - - Assert.NotNull(completionItem); - - CompletionItem updatedCompletionItem = - await this.SendRequest( - CompletionResolveRequest.Type, - completionItem); - - // Can't depend on a particular documentation string if the test machine - // hasn't run Update-Help, so just verify that a non-empty string was - // returned. - Assert.NotNull(updatedCompletionItem); - Assert.True(updatedCompletionItem.Documentation.Length > 0); - } - - [Fact] - public async Task CompletesDetailOnFilePathSuggestion() - { - string expectedPathSnippet; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - expectedPathSnippet = @".\TestFiles\CompleteFunctionName.ps1"; - } - else - { - expectedPathSnippet = "./TestFiles/CompleteFunctionName.ps1"; - } - - // Change dir to root of this test project's folder - await this.SetLocationForServerTest(this.TestRootDir); - - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1")); - - CompletionItem[] completions = - await this.SendRequest( - CompletionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1") - }, - Position = new Position - { - Line = 8, - Character = 35 - } - }); - - CompletionItem completionItem = - completions - .FirstOrDefault( - c => c.InsertText == expectedPathSnippet); - - Assert.NotNull(completionItem); - Assert.Equal(InsertTextFormat.PlainText, completionItem.InsertTextFormat); - } - - [Fact] - public async Task CompletesDetailOnFolderPathSuggestion() - { - string expectedPathSnippet; - InsertTextFormat insertTextFormat; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - expectedPathSnippet = @"'.\TestFiles\Folder With Spaces$0'"; - insertTextFormat = InsertTextFormat.Snippet; - } - else - { - expectedPathSnippet = @"'./TestFiles/Folder With Spaces$0'"; - insertTextFormat = InsertTextFormat.Snippet; - } - - // Change dir to root of this test project's folder - await this.SetLocationForServerTest(this.TestRootDir); - - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1")); - - CompletionItem[] completions = - await this.SendRequest( - CompletionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/CompleteFunctionName.ps1") - }, - Position = new Position - { - Line = 7, - Character = 32 - } - }); - - CompletionItem completionItem = - completions - .FirstOrDefault( - c => c.InsertText == expectedPathSnippet); - - Assert.NotNull(completionItem); - Assert.Equal(insertTextFormat, completionItem.InsertTextFormat); - } - - [Fact] - public async Task FindsReferencesOfVariable() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - Location[] locations = - await this.SendRequest( - ReferencesRequest.Type, - new ReferencesParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 7, - Character = 4, - } - }); - - Assert.NotNull(locations); - Assert.Equal(3, locations.Length); - - Assert.Equal(5, locations[0].Range.Start.Line); - Assert.Equal(0, locations[0].Range.Start.Character); - Assert.Equal(7, locations[1].Range.Start.Line); - Assert.Equal(0, locations[1].Range.Start.Character); - Assert.Equal(8, locations[2].Range.Start.Line); - Assert.Equal(12, locations[2].Range.Start.Character); - } - - [Fact] - public async Task FindsNoReferencesOfEmptyLine() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - Location[] locations = - await this.SendRequest( - ReferencesRequest.Type, - new ReferencesParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 9, - Character = 0, - } - }); - - Assert.NotNull(locations); - Assert.Empty(locations); - } - - [Fact] - public async Task FindsReferencesOnFunctionDefinition() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - Location[] locations = - await this.SendRequest( - ReferencesRequest.Type, - new ReferencesParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 0, - Character = 17, - } - }); - - Assert.NotNull(locations); - Assert.Equal(3, locations.Length); - - Assert.Equal(0, locations[0].Range.Start.Line); - Assert.Equal(9, locations[0].Range.Start.Character); - Assert.Equal(2, locations[1].Range.Start.Line); - Assert.Equal(4, locations[1].Range.Start.Character); - Assert.Equal(8, locations[2].Range.Start.Line); - Assert.Equal(0, locations[2].Range.Start.Character); - } - - [Fact] - public async Task FindsReferencesOnCommand() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - Location[] locations = - await this.SendRequest( - ReferencesRequest.Type, - new ReferencesParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 0, - Character = 17, - } - }); - - Assert.NotNull(locations); - Assert.Equal(3, locations.Length); - - Assert.Equal(0, locations[0].Range.Start.Line); - Assert.Equal(9, locations[0].Range.Start.Character); - Assert.Equal(2, locations[1].Range.Start.Line); - Assert.Equal(4, locations[1].Range.Start.Character); - Assert.Equal(8, locations[2].Range.Start.Line); - Assert.Equal(0, locations[2].Range.Start.Character); - } - - [Fact] - public async Task FindsDefinitionOfCommand() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - Location[] locations = - await this.SendRequest( - DefinitionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1"), - }, - Position = new Position - { - Line = 2, - Character = 11, - } - }); - - Assert.NotNull(locations); - Assert.Single(locations); - Assert.Equal(0, locations[0].Range.Start.Line); - Assert.Equal(9, locations[0].Range.Start.Character); - } - - [Fact] - public async Task FindsNoDefinitionOfBuiltinCommand() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - Location[] locations = - await this.SendRequest( - DefinitionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 10, - Character = 9, - } - }); - - Assert.NotNull(locations); - Assert.Empty(locations); - } - - [Fact] - public async Task FindsDefinitionOfVariable() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - Location[] locations = - await this.SendRequest( - DefinitionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 8, - Character = 13, - } - }); - - Assert.NotNull(locations); - Assert.Single(locations); - Assert.Equal(5, locations[0].Range.Start.Line); - Assert.Equal(0, locations[0].Range.Start.Character); - Assert.Equal(5, locations[0].Range.End.Line); - Assert.Equal(7, locations[0].Range.End.Character); - } - - [Fact] - public async Task FindsDefinitionOfVariableInOtherFile() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - Location[] locations = - await this.SendRequest( - DefinitionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 15, - Character = 20, - } - }); - - Assert.NotNull(locations); - Assert.Single(locations); - Assert.EndsWith("VariableDefinition.ps1", locations[0].Uri); - Assert.Equal(0, locations[0].Range.Start.Line); - Assert.Equal(0, locations[0].Range.Start.Character); - Assert.Equal(0, locations[0].Range.End.Line); - Assert.Equal(20, locations[0].Range.End.Character); - } - - [Fact] - public async Task FindDefinitionOfVariableWithSpecialChars() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - Location[] locations = - await this.SendRequest( - DefinitionRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 18, - Character = 24, - } - }); - - Assert.NotNull(locations); - Assert.Single(locations); - Assert.EndsWith("FindReferences.ps1", locations[0].Uri); - Assert.Equal(17, locations[0].Range.Start.Line); - Assert.Equal(0, locations[0].Range.Start.Character); - Assert.Equal(17, locations[0].Range.End.Line); - Assert.Equal(27, locations[0].Range.End.Character); - } - - [Fact] - public async Task FindsOccurencesOnFunctionDefinition() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - DocumentHighlight[] highlights = - await this.SendRequest( - DocumentHighlightRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 0, - Character = 17, - } - }); - - Assert.NotNull(highlights); - Assert.Equal(3, highlights.Length); - Assert.Equal(2, highlights[1].Range.Start.Line); - } - - [Fact] - public async Task GetsParameterHintsOnCommand() - { - await this.SendOpenFileEvent(TestUtilities.NormalizePath("TestFiles/FindReferences.ps1")); - - SignatureHelp signatureHelp = - await this.SendRequest( - SignatureHelpRequest.Type, - new TextDocumentPositionParams - { - TextDocument = new TextDocumentIdentifier - { - Uri = TestUtilities.NormalizePath("TestFiles/FindReferences.ps1") - }, - Position = new Position - { - Line = 12, - Character = 14 - } - }); - - Assert.NotNull(signatureHelp); - Assert.Single(signatureHelp.Signatures); - Assert.Equal(2, signatureHelp.Signatures[0].Parameters.Length); - Assert.Equal( - "Write-Output [-InputObject] [-NoEnumerate] []", - signatureHelp.Signatures[0].Label); - } - - [Fact] - public async Task ServiceExecutesReplCommandAndReceivesOutput() - { - OutputReader outputReader = new OutputReader(this.messageHandlers); - - // Send the configuration request to initiate the command loop - await this.SendConfigurationRequest(outputReader); - - await - this.SendRequest( - EvaluateRequest.Type, - new EvaluateRequestArguments - { - Expression = "1 + 2" - }); - - Assert.Equal("1 + 2", await outputReader.ReadLine()); - Assert.Equal("3", await outputReader.ReadLine()); - } - - [Fact] - public async Task ServiceExpandsAliases() - { - string expandedText = - await this.SendRequest( - ExpandAliasRequest.Type, - TestUtilities.NormalizeNewlines("gci\npwd")); - - Assert.Equal(TestUtilities.NormalizeNewlines("Get-ChildItem\nGet-Location"), expandedText); - } - - [Fact] - public async Task ServiceExecutesReplCommandAndReceivesChoicePrompt() - { - OutputReader outputReader = new OutputReader(this.messageHandlers); - - // Send the configuration request to initiate the command loop - await this.SendConfigurationRequest(outputReader); - - string choiceScript = - @" - $caption = ""Test Choice""; - $message = ""Make a selection""; - $choiceA = New-Object System.Management.Automation.Host.ChoiceDescription ""&Apple"",""Help for Apple""; - $choiceB = New-Object System.Management.Automation.Host.ChoiceDescription ""Banana"",""Help for Banana""; - $choices = [System.Management.Automation.Host.ChoiceDescription[]]($choiceA,$choiceB); - $host.ui.PromptForChoice($caption, $message, $choices, 1)"; - - Task>> choicePromptTask = - this.WaitForRequest(ShowChoicePromptRequest.Type); - - // Execute the script but don't await the task yet because - // the choice prompt will block execution from completing - Task evaluateTask = - this.SendRequest( - EvaluateRequest.Type, - new EvaluateRequestArguments - { - Expression = choiceScript, - Context = "repl" - }); - - // Wait for the choice prompt request and check expected values - Tuple> requestResponseContext = await choicePromptTask; - ShowChoicePromptRequest showChoicePromptRequest = requestResponseContext.Item1; - RequestContext requestContext = requestResponseContext.Item2; - - Assert.Equal(1, showChoicePromptRequest.DefaultChoices[0]); - - // Respond to the prompt request - await requestContext.SendResultAsync( - new ShowChoicePromptResponse - { - ResponseText = "a" - }); - - // Skip the initial script and prompt lines (6 script lines plus 3 prompt lines) - string[] outputLines = await outputReader.ReadLines(9); - - // Wait for the selection to appear as output - await evaluateTask; - Assert.Equal("0", await outputReader.ReadLine()); - } - - [Fact] - public async Task ServiceExecutesReplCommandAndReceivesInputPrompt() - { - OutputReader outputReader = new OutputReader(this.messageHandlers); - - // Send the configuration request to initiate the command loop - await this.SendConfigurationRequest(outputReader); - - string promptScript = - @" - $NameField = New-Object System.Management.Automation.Host.FieldDescription ""Name"" - $NameField.SetParameterType([System.String]) - $fields = [System.Management.Automation.Host.FieldDescription[]]($NameField) - $host.ui.Prompt($null, $null, $fields)"; - - Task>> inputPromptTask = - this.WaitForRequest(ShowInputPromptRequest.Type); - - // Execute the script but don't await the task yet because - // the choice prompt will block execution from completing - Task evaluateTask = - this.SendRequest( - EvaluateRequest.Type, - new EvaluateRequestArguments - { - Expression = promptScript, - Context = "repl" - }); - - // Wait for the input prompt request and check expected values - Tuple> requestResponseContext = await inputPromptTask; - ShowInputPromptRequest showInputPromptRequest = requestResponseContext.Item1; - RequestContext requestContext = requestResponseContext.Item2; - - Assert.Equal("Name", showInputPromptRequest.Name); - - // Respond to the prompt request - await requestContext.SendResultAsync( - new ShowInputPromptResponse - { - ResponseText = "John" - }); - - // Skip the initial 4 script lines - string[] scriptLines = await outputReader.ReadLines(4); - - // Verify the first line - Assert.Equal("Name: John", await outputReader.ReadLine()); - - // Verify the rest of the output - string[] outputLines = await outputReader.ReadLines(4); - Assert.Equal("", outputLines[0]); - Assert.Equal("Key Value", outputLines[1]); - Assert.Equal("--- -----", outputLines[2]); - Assert.Equal("Name John ", outputLines[3]); - - // Wait for execution to complete - await evaluateTask; - } - - [Fact(Skip = "Native command output in the legacy host has been disabled for now, may re-enable later")] - public async Task ServiceExecutesNativeCommandAndReceivesCommand() - { - OutputReader outputReader = new OutputReader(this.messageHandlers); - - // Execute the script but don't await the task yet because - // the choice prompt will block execution from completing - Task evaluateTask = - this.SendRequest( - EvaluateRequest.Type, - new EvaluateRequestArguments - { - Expression = "cmd.exe /c 'echo Test Output'", - Context = "repl" - }); - - // Skip the command line and the following newline - await outputReader.ReadLines(2); - - // Wait for the selection to appear as output - await evaluateTask; - Assert.Equal("Test Output", await outputReader.ReadLine()); - } - - [Fact] - public async Task ServiceLoadsProfilesOnDemand() - { - string testHostName = "Test.PowerShellEditorServices"; - string profileName = - string.Format( - "{0}_{1}", - testHostName, - ProfilePaths.AllHostsProfileName); - string testProfilePath = - Path.Combine( - Path.GetFullPath( - TestUtilities.NormalizePath("../../../../PowerShellEditorServices.Test.Shared/Profile/")), - profileName); - - string currentUserCurrentHostPath = - Path.Combine( -#if !CoreCLR - Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), - "WindowsPowerShell", -#else - // TODO: This will need to be improved once we are running tests on CoreCLR - "~/.powershell", -#endif - profileName); - - // Copy the test profile to the current user's host profile path - File.Copy(testProfilePath, currentUserCurrentHostPath, true); - - Assert.True( - File.Exists(currentUserCurrentHostPath), - "Copied profile path does not exist!"); - - OutputReader outputReader = new OutputReader(this.messageHandlers); - - // Send the configuration change to cause profiles to be loaded - await this.SendConfigurationRequest(outputReader, true); - - Task evaluateTask = - this.SendRequest( - EvaluateRequest.Type, - new EvaluateRequestArguments - { - Expression = "\"PROFILE: $(Assert-ProfileLoaded)\"", - Context = "repl" - }); - - // Try reading up to 10 lines to find the expected output line - string outputString = null; - for (int i = 0; i < 10; i++) - { - outputString = await outputReader.ReadLine(); - - if (outputString.StartsWith("PROFILE")) - { - break; - } - } - - // Delete the test profile before any assert failures - // cause the function to exit - File.Delete(currentUserCurrentHostPath); - - // Wait for the selection to appear as output - await evaluateTask; - Assert.Equal("PROFILE: True", outputString); - } - - public async Task ServiceReturnsPowerShellVersionDetails() - { - PowerShellVersion versionDetails = - await this.SendRequest( - PowerShellVersionRequest.Type, - new PowerShellVersionRequest()); - - // TODO: This should be more robust and predictable. - Assert.StartsWith("5.", versionDetails.Version); - Assert.StartsWith("5.", versionDetails.DisplayVersion); - Assert.Equal("Desktop", versionDetails.Edition); - - string expectedArchitecture = (IntPtr.Size == 8) ? "x64" : "x86"; - Assert.Equal(expectedArchitecture, versionDetails.Architecture); - } - - private string TestRootDir - { - get - { - string assemblyDir = Path.GetDirectoryName(this.GetType().Assembly.Location); - return Path.Combine(assemblyDir, @"..\..\.."); - } - } - - private async Task SetLocationForServerTest(string path) - { - // Change dir to root of this test project's folder - await this.SendRequest( - EvaluateRequest.Type, - new EvaluateRequestArguments - { - Expression = $"Set-Location {path}", - Context = "repl" - }); - } - - private async Task SendOpenFileEvent(string filePath, bool waitForDiagnostics = true) - { - string fileContents = string.Join(Environment.NewLine, File.ReadAllLines(filePath)); - - // Start the event waiter for diagnostics before sending the - // open event to make sure that we catch it - Task diagnosticWaitTask = null; - if (waitForDiagnostics) - { - // Wait for the diagnostic event - diagnosticWaitTask = - this.WaitForEvent( - PublishDiagnosticsNotification.Type); - } - - await this.SendEvent( - DidOpenTextDocumentNotification.Type, - new DidOpenTextDocumentParams - { - TextDocument = new TextDocumentItem - { - Uri = filePath, - Text = fileContents, - LanguageId = "PowerShell", - Version = 0 - } - }); - - if (diagnosticWaitTask != null) - { - await diagnosticWaitTask; - } - } - - private async Task SendConfigurationRequest( - OutputReader outputReader, - bool enableProfileLoading = false) - { - // Send the configuration change to cause profiles to be loaded - await this.languageServiceClient.SendEventAsync( - DidChangeConfigurationNotification.Type, - new DidChangeConfigurationParams - { - Settings = new LanguageServerSettingsWrapper - { - Powershell = new LanguageServerSettings - { - EnableProfileLoading = enableProfileLoading, - ScriptAnalysis = new ScriptAnalysisSettings - { - Enable = false - }, - CodeFormatting = new CodeFormattingSettings() - } - } - }); - - // Wait for the prompt to be written once the profile loads - Assert.StartsWith("PS ", await outputReader.ReadLine(waitForNewLine: false)); - } - } -} diff --git a/test/PowerShellEditorServices.Test.Host/OutputReader.cs b/test/PowerShellEditorServices.Test.Host/OutputReader.cs deleted file mode 100644 index c2732bd85..000000000 --- a/test/PowerShellEditorServices.Test.Host/OutputReader.cs +++ /dev/null @@ -1,139 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter; -using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; -using Microsoft.PowerShell.EditorServices.Utility; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.PowerShell.EditorServices.Test.Host -{ - internal class OutputReader - { - private AsyncQueue outputQueue = new AsyncQueue(); - - private string currentOutputCategory; - private Queue> bufferedOutput = new Queue>(); - - public OutputReader(IMessageHandlers messageHandlers) - { - messageHandlers.SetEventHandler( - OutputEvent.Type, - this.OnOutputEvent); - } - - public async Task ReadLine(string expectedOutputCategory = "stdout", bool waitForNewLine = true) - { - try - { - bool lineHasNewLine = false; - string[] outputLines = null; - string nextOutputString = string.Empty; - - // Wait no longer than 7 seconds for output to come back - CancellationToken cancellationToken = - Debugger.IsAttached - ? CancellationToken.None - : new CancellationTokenSource(7000).Token; - - // Any lines in the buffer? - if (this.bufferedOutput.Count > 0) - { - Assert.Equal(expectedOutputCategory, this.currentOutputCategory); - - // Return the first buffered line - var lineTuple = this.bufferedOutput.Dequeue(); - nextOutputString = lineTuple.Item1; - lineHasNewLine = lineTuple.Item2; - } - - // Loop until we get a full line of output - while (!lineHasNewLine) - { - // Execution reaches this point if a buffered line wasn't available - Task outputTask = - this.outputQueue.DequeueAsync( - cancellationToken); - OutputEventBody nextOutputEvent = await outputTask; - - // Verify that the output is of the expected type - Assert.Equal(expectedOutputCategory, nextOutputEvent.Category); - this.currentOutputCategory = nextOutputEvent.Category; - - // Split up the output into multiple lines - outputLines = - nextOutputEvent.Output.Split( - new string[] { "\n", "\r\n" }, - StringSplitOptions.None); - - // Add the first bit of output to the existing string - nextOutputString += outputLines[0]; - - // Have we found a newline now? - lineHasNewLine = - outputLines.Length > 1 || - nextOutputEvent.Output.EndsWith("\n"); - - // Buffer any remaining lines for future reads - if (outputLines.Length > 1) - { - for (int i = 1; i < outputLines.Length; i++) - { - this.bufferedOutput.Enqueue( - new Tuple( - outputLines[i], - - // The line has a newline if it's not the last segment or - // if the last segment is not an empty string and the - // complete output string ends with a newline - i < outputLines.Length - 1 || - (outputLines[outputLines.Length - 1].Length > 0 && - nextOutputEvent.Output.EndsWith("\n")))); - } - } - - // At this point, the state of lineHasNewLine will determine - // whether the loop continues to wait for another output - // event that completes the current line. - if (!waitForNewLine) - { - break; - } - } - - return nextOutputString; - } - catch (TaskCanceledException) - { - throw new TimeoutException("Timed out waiting for an input line."); - } - } - - public async Task ReadLines(int lineCount, string expectedOutputCategory = "stdout") - { - List outputLines = new List(); - - for (int i = 0; i < lineCount; i++) - { - outputLines.Add( - await this.ReadLine( - expectedOutputCategory)); - } - - return outputLines.ToArray(); - } - - private async Task OnOutputEvent(OutputEventBody outputEvent, EventContext context) - { - await this.outputQueue.EnqueueAsync(outputEvent); - } - } -} - diff --git a/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj b/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj deleted file mode 100644 index 6a2339e57..000000000 --- a/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - netcoreapp2.1;net461 - Microsoft.PowerShell.EditorServices.Test.Host - - - - PreserveNewest - - - - - - - - $(DefineConstants);CoreCLR - - - - - - - - - - - - - - - - diff --git a/test/PowerShellEditorServices.Test.Host/ServerTestsBase.cs b/test/PowerShellEditorServices.Test.Host/ServerTestsBase.cs deleted file mode 100644 index e805d85cd..000000000 --- a/test/PowerShellEditorServices.Test.Host/ServerTestsBase.cs +++ /dev/null @@ -1,316 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol; -using Microsoft.PowerShell.EditorServices.Test.Shared; -using Microsoft.PowerShell.EditorServices.Utility; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Concurrent; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.PowerShell.EditorServices.Test.Host -{ - public class ServerTestsBase - { - private static int sessionCounter; - private Process serviceProcess; - protected IMessageSender messageSender; - protected IMessageHandlers messageHandlers; - - private ConcurrentDictionary> eventQueuePerType = - new ConcurrentDictionary>(); - - private ConcurrentDictionary> requestQueuePerType = - new ConcurrentDictionary>(); - - protected async Task> LaunchService( - string logPath, - bool waitForDebugger = false) - { - string modulePath = Path.GetFullPath(TestUtilities.NormalizePath("../../../../../module")); - string scriptPath = Path.GetFullPath(Path.Combine(modulePath, "PowerShellEditorServices", "Start-EditorServices.ps1")); - - if (!File.Exists(scriptPath)) - { - throw new IOException(String.Format("Bad start script path: '{0}'", scriptPath)); - } - - Assembly assembly = this.GetType().GetTypeInfo().Assembly; - - string assemblyPath = new Uri(assembly.CodeBase).LocalPath; - FileVersionInfo fileVersionInfo = - FileVersionInfo.GetVersionInfo(assemblyPath); - - string sessionPath = - Path.Combine( - Path.GetDirectoryName(assemblyPath), $"session-{++sessionCounter}.json"); - - if (File.Exists(sessionPath)) - { - File.Delete(sessionPath); - } - - string editorServicesModuleVersion = - string.Format( - "{0}.{1}.{2}", - fileVersionInfo.FileMajorPart, - fileVersionInfo.FileMinorPart, - fileVersionInfo.FileBuildPart); - - string scriptArgs = - "\"" + scriptPath + "\" " + - "-HostName \\\"PowerShell Editor Services Test Host\\\" " + - "-HostProfileId \"Test.PowerShellEditorServices\" " + - "-HostVersion \"1.0.0\" " + - "-BundledModulesPath \\\"" + modulePath + "\\\" " + - "-LogLevel \"Verbose\" " + - "-LogPath \"" + logPath + "\" " + - "-SessionDetailsPath \"" + sessionPath + "\" " + - "-FeatureFlags @() " + - "-AdditionalModules @() "; - - if (waitForDebugger) - { - scriptArgs += "-WaitForDebugger "; - } - - string[] args = - new string[] - { - "-NoProfile", - "-NonInteractive", - "-ExecutionPolicy", "Unrestricted", - "-Command \"" + scriptArgs + "\"" - }; - - this.serviceProcess = new Process - { - StartInfo = new ProcessStartInfo - { - FileName = GetPwshExeName(), - Arguments = string.Join(" ", args), - CreateNoWindow = true, - UseShellExecute = false, - RedirectStandardInput = true, - RedirectStandardOutput = true, - RedirectStandardError = true, - StandardOutputEncoding = Encoding.UTF8 - }, - EnableRaisingEvents = true, - }; - - // Start the process - this.serviceProcess.Start(); - - string sessionDetailsText = string.Empty; - - // Wait up to ~5 seconds for the server to finish initializing - var maxRetryAttempts = 10; - while (maxRetryAttempts-- > 0) - { - if (this.serviceProcess.HasExited) - { - throw new Exception(String.Format("Server host process quit unexpectedly: '{0}'", this.serviceProcess.StandardError.ReadToEnd())); - } - - try - { - using (var stream = new FileStream(sessionPath, FileMode.Open, FileAccess.Read, FileShare.None)) - using (var reader = new StreamReader(stream)) - { - sessionDetailsText = reader.ReadToEnd(); - break; - } - } - catch (Exception ex) - { - Debug.WriteLine($"Session details at '{sessionPath}' not available: {ex.Message}"); - } - - Thread.Sleep(500); - } - - JObject result = JObject.Parse(sessionDetailsText); - if (result["status"].Value() == "started") - { - return new Tuple( - result["languageServicePipeName"].Value(), - result["debugServicePipeName"].Value()); - } - - Debug.WriteLine($"Failed to read session details from '{sessionPath}'"); - - return null; - } - - protected void KillService() - { - try - { - this.serviceProcess.Kill(); - } - catch (InvalidOperationException) - { - // This exception gets thrown if the server process has - // already existed by the time Kill gets called. - } - } - - protected Task SendRequest( - RequestType requestType, - TParams requestParams) - { - return - this.messageSender.SendRequestAsync( - requestType, - requestParams, - true); - } - - protected Task SendEvent(NotificationType eventType, TParams eventParams) - { - return - this.messageSender.SendEventAsync( - eventType, - eventParams); - } - - protected void QueueEventsForType(NotificationType eventType) - { - var eventQueue = - this.eventQueuePerType.AddOrUpdate( - eventType.Method, - new AsyncQueue(), - (key, queue) => queue); - - this.messageHandlers.SetEventHandler( - eventType, - (p, ctx) => - { - return eventQueue.EnqueueAsync(p); - }); - } - - protected async Task WaitForEvent( - NotificationType eventType, - int timeoutMilliseconds = 5000) - { - Task eventTask = null; - - // Use the event queue if one has been registered - AsyncQueue eventQueue = null; - if (this.eventQueuePerType.TryGetValue(eventType.Method, out eventQueue)) - { - eventTask = - eventQueue - .DequeueAsync() - .ContinueWith( - task => (TParams)task.Result); - } - else - { - TaskCompletionSource eventTaskSource = new TaskCompletionSource(); - - this.messageHandlers.SetEventHandler( - eventType, - (p, ctx) => - { - if (!eventTaskSource.Task.IsCompleted) - { - eventTaskSource.SetResult(p); - } - - return Task.FromResult(true); - }); - - eventTask = eventTaskSource.Task; - } - - await - Task.WhenAny( - eventTask, - Task.Delay(timeoutMilliseconds)); - - if (!eventTask.IsCompleted) - { - throw new TimeoutException( - string.Format( - "Timed out waiting for '{0}' event!", - eventType.Method)); - } - - return await eventTask; - } - - protected async Task>> WaitForRequest( - RequestType requestType, - int timeoutMilliseconds = 5000) - { - Task>> requestTask = null; - - // Use the request queue if one has been registered - AsyncQueue requestQueue = null; - if (this.requestQueuePerType.TryGetValue(requestType.Method, out requestQueue)) - { - requestTask = - requestQueue - .DequeueAsync() - .ContinueWith( - task => (Tuple>)task.Result); - } - else - { - var requestTaskSource = - new TaskCompletionSource>>(); - - this.messageHandlers.SetRequestHandler( - requestType, - (p, ctx) => - { - if (!requestTaskSource.Task.IsCompleted) - { - requestTaskSource.SetResult( - new Tuple>(p, ctx)); - } - - return Task.FromResult(true); - }); - - requestTask = requestTaskSource.Task; - } - - await - Task.WhenAny( - requestTask, - Task.Delay(timeoutMilliseconds)); - - if (!requestTask.IsCompleted) - { - throw new TimeoutException( - string.Format( - "Timed out waiting for '{0}' request!", - requestType.Method)); - } - - return await requestTask; - } - - private static string GetPwshExeName() - { -#if !CoreCLR - return "powershell.exe"; -#else - return "pwsh"; -#endif - } - } -} diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/ChildModule/ChildModule.psm1 b/test/PowerShellEditorServices.Test.Host/TestFiles/ChildModule/ChildModule.psm1 deleted file mode 100644 index b13e23032..000000000 --- a/test/PowerShellEditorServices.Test.Host/TestFiles/ChildModule/ChildModule.psm1 +++ /dev/null @@ -1,2 +0,0 @@ -function Get-Stuff { -} \ No newline at end of file diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/CompleteFunctionName.ps1 b/test/PowerShellEditorServices.Test.Host/TestFiles/CompleteFunctionName.ps1 deleted file mode 100644 index d7f9b9aab..000000000 --- a/test/PowerShellEditorServices.Test.Host/TestFiles/CompleteFunctionName.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -function My-Function -{ -} -$Cons -My- -Get-Proc -$HKC -Get-ChildItem ./TestFiles/Folder -Get-ChildItem ./TestFiles/CompleteF diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/FindReferences.ps1 b/test/PowerShellEditorServices.Test.Host/TestFiles/FindReferences.ps1 deleted file mode 100644 index ed82df5e4..000000000 --- a/test/PowerShellEditorServices.Test.Host/TestFiles/FindReferences.ps1 +++ /dev/null @@ -1,19 +0,0 @@ -function My-Function ($myInput) -{ - My-Function $myInput -} - -$things = 4 - -$things -My-Function $things - -Write-Output "Hi"; - -Write-Output "" - -. .\VariableDefinition.ps1 -Write-Output $variableInOtherFile - -${variable-with-weird-name} = "this variable has special characters" -Write-Output ${variable-with-weird-name} diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/Folder With Spaces/.gitkeep b/test/PowerShellEditorServices.Test.Host/TestFiles/Folder With Spaces/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/Module.psm1 b/test/PowerShellEditorServices.Test.Host/TestFiles/Module.psm1 deleted file mode 100644 index 5fb8eeb7c..000000000 --- a/test/PowerShellEditorServices.Test.Host/TestFiles/Module.psm1 +++ /dev/null @@ -1 +0,0 @@ -using module ".\ChildModule" \ No newline at end of file diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/MultiLineReplace.ps1 b/test/PowerShellEditorServices.Test.Host/TestFiles/MultiLineReplace.ps1 deleted file mode 100644 index 2589dd3e0..000000000 --- a/test/PowerShellEditorServices.Test.Host/TestFiles/MultiLineReplace.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -first -secoXX -XXfth \ No newline at end of file diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/SimpleSemanticError.ps1 b/test/PowerShellEditorServices.Test.Host/TestFiles/SimpleSemanticError.ps1 deleted file mode 100644 index a4956a97a..000000000 --- a/test/PowerShellEditorServices.Test.Host/TestFiles/SimpleSemanticError.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -function Do-Work { - # This should trigger the PSUseApprovedVerbs rule -} \ No newline at end of file diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/SimpleSyntaxError.ps1 b/test/PowerShellEditorServices.Test.Host/TestFiles/SimpleSyntaxError.ps1 deleted file mode 100644 index 94092ebc9..000000000 --- a/test/PowerShellEditorServices.Test.Host/TestFiles/SimpleSyntaxError.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -# Should complain about lacking function body -function MyFunc -} \ No newline at end of file diff --git a/test/PowerShellEditorServices.Test.Host/TestFiles/VariableDefinition.ps1 b/test/PowerShellEditorServices.Test.Host/TestFiles/VariableDefinition.ps1 deleted file mode 100644 index c9f4548ec..000000000 --- a/test/PowerShellEditorServices.Test.Host/TestFiles/VariableDefinition.ps1 +++ /dev/null @@ -1 +0,0 @@ -$variableInOtherFile = "some value" diff --git a/test/PowerShellEditorServices.Test.Host/xunit.runner.json b/test/PowerShellEditorServices.Test.Host/xunit.runner.json deleted file mode 100644 index 88c056c3d..000000000 --- a/test/PowerShellEditorServices.Test.Host/xunit.runner.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "parallelizeTestCollections": false, - "methodDisplay": "method" -} \ No newline at end of file From bc79f874ae9c3f61ec5692748b052a2a449e665d Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 16 Mar 2021 11:45:25 -0700 Subject: [PATCH 2/6] Fix .NET and PowerShell versions for tests PowerShell 6.2 hit end of life, so we removed it. New lowest common denominator is PowerShell 7, with `netcoreapp3.1` (upgraded from `netcoreapp2.1`). PowerShell 7.1 was updated to 7.2, along with a corresponding update from `net5.0` to `net6.0`. --- PowerShellEditorServices.build.ps1 | 19 +++++++++---------- .../PowerShellEditorServices.Hosting.csproj | 4 ++-- .../PowerShellEditorServices.Test.E2E.csproj | 2 +- .../PowerShellEditorServices.Test.csproj | 11 ++++------- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index 99b0cd823..90c393cc1 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -24,14 +24,13 @@ $script:PsesCommonProps = [xml](Get-Content -Raw "$PSScriptRoot/PowerShellEditor $script:IsPreview = [bool]($script:PsesCommonProps.Project.PropertyGroup.VersionSuffix) $script:NetRuntime = @{ - PS62 = 'netcoreapp2.1' PS7 = 'netcoreapp3.1' - PS71 = 'net5.0' + PS72 = 'net6.0' Desktop = 'net461' Standard = 'netstandard2.0' } -$script:HostCoreOutput = "$PSScriptRoot/src/PowerShellEditorServices.Hosting/bin/$Configuration/$($script:NetRuntime.PS62)/publish" +$script:HostCoreOutput = "$PSScriptRoot/src/PowerShellEditorServices.Hosting/bin/$Configuration/$($script:NetRuntime.PS7)/publish" $script:HostDeskOutput = "$PSScriptRoot/src/PowerShellEditorServices.Hosting/bin/$Configuration/$($script:NetRuntime.Desktop)/publish" $script:PsesOutput = "$PSScriptRoot/src/PowerShellEditorServices/bin/$Configuration/$($script:NetRuntime.Standard)/publish" $script:VSCodeOutput = "$PSScriptRoot/src/PowerShellEditorServices.VSCode/bin/$Configuration/$($script:NetRuntime.Standard)/publish" @@ -103,7 +102,7 @@ function Install-Dotnet { Write-Host '.NET installation complete' -ForegroundColor Green } -task SetupDotNet -Before Clean, Build, TestServerWinPS, TestServerPS7, TestServerPS71, TestE2E { +task SetupDotNet -Before Clean, Build, TestServerWinPS, TestServerPS7, TestServerPS72, TestE2E { $dotnetPath = "$PSScriptRoot/.dotnet" $dotnetExePath = if ($script:IsUnix) { "$dotnetPath/dotnet" } else { "$dotnetPath/dotnet.exe" } @@ -237,7 +236,7 @@ task SetupHelpForTests { task Build BinClean,{ exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices\PowerShellEditorServices.csproj -f $script:NetRuntime.Standard } - exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.PS62 } + exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.PS7 } if (-not $script:IsUnix) { exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.Desktop } @@ -254,7 +253,7 @@ function DotNetTestFilter { task Test SetupHelpForTests,TestServer,TestE2E -task TestServer TestServerWinPS,TestServerPS7,TestServerPS71 +task TestServer TestServerWinPS,TestServerPS7,TestServerPS72 task TestServerWinPS -If (-not $script:IsUnix) { Set-Location .\test\PowerShellEditorServices.Test\ @@ -268,10 +267,10 @@ task TestServerPS7 { } } -task TestServerPS71 { +task TestServerPS72 { Set-Location .\test\PowerShellEditorServices.Test\ Invoke-WithCreateDefaultHook -NewModulePath $script:PSCoreModulePath { - exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS71 (DotNetTestFilter) } + exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS72 (DotNetTestFilter) } } } @@ -279,13 +278,13 @@ task TestE2E { Set-Location .\test\PowerShellEditorServices.Test.E2E\ $env:PWSH_EXE_NAME = if ($IsCoreCLR) { "pwsh" } else { "powershell" } - exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS62 (DotNetTestFilter) } + exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS7 (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.PS62 (DotNetTestFilter) } + exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS7 (DotNetTestFilter) } } finally { [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", $null, [System.EnvironmentVariableTarget]::Machine); } diff --git a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj index 4ed3b7a8c..72f621c02 100644 --- a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj +++ b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj @@ -1,12 +1,12 @@  - netcoreapp2.1;net461 + netcoreapp3.1;net461 Microsoft.PowerShell.EditorServices.Hosting latest - + $(DefineConstants);CoreCLR diff --git a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj index b217711c1..05b71c091 100644 --- a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj +++ b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj @@ -1,7 +1,7 @@ - netcoreapp2.1 + netcoreapp3.1 false diff --git a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj index 536e60420..6f47ad923 100644 --- a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj +++ b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj @@ -1,7 +1,7 @@  - net5.0;netcoreapp3.1;net461 + net6.0;netcoreapp3.1;net461 Microsoft.PowerShell.EditorServices.Test x64 @@ -13,14 +13,11 @@ - - + + - - - - + From 025c4120e0a65b0d5b461692096f43a9b436f504 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 16 Mar 2021 12:07:45 -0700 Subject: [PATCH 3/6] Bump CI images --- .vsts-ci/azure-pipelines-ci.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.vsts-ci/azure-pipelines-ci.yml b/.vsts-ci/azure-pipelines-ci.yml index 42552876c..d9ff9a82d 100644 --- a/.vsts-ci/azure-pipelines-ci.yml +++ b/.vsts-ci/azure-pipelines-ci.yml @@ -32,33 +32,35 @@ trigger: - /LICENSE - /CODE_OF_CONDUCT.md +# TODO: Setup matrix of image support. jobs: - job: 'PS51_Win10' displayName: PowerShell 5.1 | Windows 10 pool: + # TODO: Update this image. vmImage: 'vs2017-win2016' steps: - template: templates/ci-general.yml parameters: pwsh: false -- job: 'PS6_Win10' - displayName: PowerShell 6 | Windows 10 +- job: 'PS7_Win10' + displayName: PowerShell 7 | Windows 10 pool: - vmImage: 'vs2017-win2016' + vmImage: 'windows-2019' steps: - template: templates/ci-general.yml -- job: 'PS6_macOS' - displayName: PowerShell 6 | macOS +- job: 'PS7_macOS' + displayName: PowerShell 7 | macOS pool: - vmImage: 'macOS-10.14' + vmImage: 'macOS-10.15' steps: - template: templates/ci-general.yml -- job: 'PS6_Ubuntu' - displayName: PowerShell 6 | Ubuntu +- job: 'PS7_Ubuntu' + displayName: PowerShell 7 | Ubuntu pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-20.04' steps: - template: templates/ci-general.yml From 338be80422b344f44bd3b62948b5a4808604cbda Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Tue, 16 Mar 2021 12:00:52 -0700 Subject: [PATCH 4/6] Bump `dotnet` on CI --- PowerShellEditorServices.build.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index 90c393cc1..a4443837e 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -108,7 +108,8 @@ task SetupDotNet -Before Clean, Build, TestServerWinPS, TestServerPS7, TestServe $dotnetExePath = if ($script:IsUnix) { "$dotnetPath/dotnet" } else { "$dotnetPath/dotnet.exe" } if (!(Test-Path $dotnetExePath)) { - Install-Dotnet -Channel '2.1','3.1','release/5.0.1xx-preview6' + # TODO: Test .NET 5 with PowerShell 7.1, and add that channel here. + Install-Dotnet -Channel '3.1','release/6.0.1xx-preview2' } # This variable is used internally by 'dotnet' to know where it's installed From ccba0d37371d36fccc3b981e65620ef6cf92a2e6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 17 Mar 2021 14:17:20 -0700 Subject: [PATCH 5/6] Make tests compatible with Mac M1 Which only supports .NET Core 6. --- PowerShellEditorServices.build.ps1 | 24 ++++++++++--------- .../PowerShellEditorServices.Test.E2E.csproj | 3 +-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index a4443837e..fea03e618 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -18,7 +18,8 @@ param( #Requires -Modules @{ModuleName="InvokeBuild";ModuleVersion="3.2.1"} -$script:IsUnix = $PSVersionTable.PSEdition -and $PSVersionTable.PSEdition -eq "Core" -and !$IsWindows +$script:IsNix = $IsLinux -or $IsMacOS +$script:IsRosetta = $IsMacOS -and (sysctl -n sysctl.proc_translated) -eq 1 # Mac M1 $script:BuildInfoPath = [System.IO.Path]::Combine($PSScriptRoot, "src", "PowerShellEditorServices.Hosting", "BuildInfo.cs") $script:PsesCommonProps = [xml](Get-Content -Raw "$PSScriptRoot/PowerShellEditorServices.Common.props") $script:IsPreview = [bool]($script:PsesCommonProps.Project.PropertyGroup.VersionSuffix) @@ -62,7 +63,7 @@ function Install-Dotnet { Write-Host "Installing .NET channels $Channel" -ForegroundColor Green # The install script is platform-specific - $installScriptExt = if ($script:IsUnix) { "sh" } else { "ps1" } + $installScriptExt = if ($script:IsNix) { "sh" } else { "ps1" } $installScript = "dotnet-install.$installScriptExt" # Download the official installation script and run it @@ -74,11 +75,11 @@ function Install-Dotnet { { Write-Host "`n### Installing .NET CLI $Version...`n" - if ($script:IsUnix) { + if ($script:IsNix) { chmod +x $installScriptPath } - $params = if ($script:IsUnix) + $params = if ($script:IsNix) { @('-Channel', $dotnetChannel, '-InstallDir', $env:DOTNET_INSTALL_DIR, '-NoPath', '-Verbose') } @@ -105,7 +106,7 @@ function Install-Dotnet { task SetupDotNet -Before Clean, Build, TestServerWinPS, TestServerPS7, TestServerPS72, TestE2E { $dotnetPath = "$PSScriptRoot/.dotnet" - $dotnetExePath = if ($script:IsUnix) { "$dotnetPath/dotnet" } else { "$dotnetPath/dotnet.exe" } + $dotnetExePath = if ($script:IsNix) { "$dotnetPath/dotnet" } else { "$dotnetPath/dotnet.exe" } if (!(Test-Path $dotnetExePath)) { # TODO: Test .NET 5 with PowerShell 7.1, and add that channel here. @@ -238,7 +239,7 @@ task SetupHelpForTests { task Build BinClean,{ exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices\PowerShellEditorServices.csproj -f $script:NetRuntime.Standard } exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.PS7 } - if (-not $script:IsUnix) + if (-not $script:IsNix) { exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.Desktop } } @@ -256,12 +257,12 @@ task Test SetupHelpForTests,TestServer,TestE2E task TestServer TestServerWinPS,TestServerPS7,TestServerPS72 -task TestServerWinPS -If (-not $script:IsUnix) { +task TestServerWinPS -If (-not $script:IsNix) { Set-Location .\test\PowerShellEditorServices.Test\ exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Desktop (DotNetTestFilter) } } -task TestServerPS7 { +task TestServerPS7 -If (-not $script:IsRosetta) { Set-Location .\test\PowerShellEditorServices.Test\ Invoke-WithCreateDefaultHook -NewModulePath $script:PSCoreModulePath { exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS7 (DotNetTestFilter) } @@ -279,10 +280,11 @@ task TestE2E { Set-Location .\test\PowerShellEditorServices.Test.E2E\ $env:PWSH_EXE_NAME = if ($IsCoreCLR) { "pwsh" } else { "powershell" } - exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS7 (DotNetTestFilter) } + $NetRuntime = if ($IsRosetta) { $script:NetRuntime.PS72 } else { $script:NetRuntime.PS7 } + exec { & $script:dotnetExe test --logger trx -f $NetRuntime (DotNetTestFilter) } # Run E2E tests in ConstrainedLanguage mode. - if (!$script:IsUnix) { + if (!$script:IsNix) { try { [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", [System.EnvironmentVariableTarget]::Machine); exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.PS7 (DotNetTestFilter) } @@ -340,7 +342,7 @@ task LayoutModule -After Build { } # PSES/bin/Desktop - if (-not $script:IsUnix) + if (-not $script:IsNix) { foreach ($hostComponent in Get-ChildItem $script:HostDeskOutput) { diff --git a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj index 05b71c091..837a6a8fd 100644 --- a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj +++ b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj @@ -1,8 +1,7 @@ - netcoreapp3.1 - + net6.0;netcoreapp3.1 false From bc2db5ce9a3de21b4e9f3edd91af1ccd206ae259 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 18 Mar 2021 12:58:13 -0700 Subject: [PATCH 6/6] Skip tests which depend on help system and so are flaky on Linux --- .../Utility/VersionUtils.cs | 6 +++--- .../LanguageServerProtocolMessageTests.cs | 13 ++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/PowerShellEditorServices/Utility/VersionUtils.cs b/src/PowerShellEditorServices/Utility/VersionUtils.cs index e2c19ab03..363f0e0d6 100644 --- a/src/PowerShellEditorServices/Utility/VersionUtils.cs +++ b/src/PowerShellEditorServices/Utility/VersionUtils.cs @@ -50,17 +50,17 @@ internal static class VersionUtils public static bool IsPS7OrGreater { get; } = PSVersion.Major >= 7; /// - /// True if we are running in on Windows, false otherwise. + /// True if we are running on Windows, false otherwise. /// public static bool IsWindows { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); /// - /// True if we are running in on macOS, false otherwise. + /// True if we are running on macOS, false otherwise. /// public static bool IsMacOS { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); /// - /// True if we are running in on Linux, false otherwise. + /// True if we are running on Linux, false otherwise. /// public static bool IsLinux { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); } diff --git a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs index 3b6af939b..d2b68d302 100644 --- a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs +++ b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -31,6 +32,9 @@ namespace PowerShellEditorServices.Test.E2E { public class LanguageServerProtocolMessageTests : IClassFixture, IDisposable { + // Borrowed from `VersionUtils` which can't be used here due to an initialization problem. + private static bool IsLinux { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + private readonly static string s_binDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); @@ -924,9 +928,10 @@ await PsesLanguageClient } [Trait("Category", "LSP")] - [Fact] + [SkippableFact] public async Task CanSendCompletionAndCompletionResolveRequestAsync() { + Skip.If(IsLinux, "This depends on the help system, which is flaky on Linux."); string filePath = NewTestFile("Write-H"); CompletionList completionItems = await PsesLanguageClient.TextDocument.RequestCompletion( @@ -950,9 +955,10 @@ public async Task CanSendCompletionAndCompletionResolveRequestAsync() } [Trait("Category", "LSP")] - [Fact] + [SkippableFact] public async Task CanSendCompletionResolveWithModulePrefixRequestAsync() { + Skip.If(IsLinux, "This depends on the help system, which is flaky on Linux."); await PsesLanguageClient .SendRequest( "evaluate", @@ -985,9 +991,10 @@ await PsesLanguageClient } [Trait("Category", "LSP")] - [Fact] + [SkippableFact] public async Task CanSendHoverRequestAsync() { + Skip.If(IsLinux, "This depends on the help system, which is flaky on Linux."); string filePath = NewTestFile("Write-Host"); Hover hover = await PsesLanguageClient.TextDocument.RequestHover(