diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj
index 562239ded..a18cc4be0 100644
--- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj
+++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj
@@ -28,8 +28,8 @@
-
-
+
+
diff --git a/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs
index 5c922e886..6e23abff2 100644
--- a/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs
+++ b/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs
@@ -228,5 +228,64 @@ public async Task CanSetBreakpointsAsync()
(i) => Assert.Equal("at breakpoint", i),
(i) => Assert.Equal("after breakpoint", i));
}
+
+ // This is a regression test for a bug where user code causes a new synchronization context
+ // to be created, breaking the extension. It's most evident when debugging PowerShell
+ // scripts that use System.Windows.Forms. It required fixing both Editor Services and
+ // OmniSharp.
+ //
+ // This test depends on PowerShell being able to load System.Windows.Forms, which only works
+ // reliably with Windows PowerShell. It works with PowerShell Core in the real-world;
+ // however, our host executable is xUnit, not PowerShell. So by restricting to Windows
+ // PowerShell, we avoid all issues with our test project (and the xUnit executable) not
+ // having System.Windows.Forms deployed, and can instead rely on the Windows Global Assembly
+ // Cache (GAC) to find it.
+ [Trait("Category", "DAP")]
+ [SkippableFact]
+ public async Task CanStepPastSystemWindowsForms()
+ {
+ Skip.IfNot(PsesStdioProcess.IsWindowsPowerShell);
+ Skip.If(PsesStdioProcess.RunningInConstainedLanguageMode);
+
+ string filePath = NewTestFile(string.Join(Environment.NewLine, new []
+ {
+ "Add-Type -AssemblyName System.Windows.Forms",
+ "$form = New-Object System.Windows.Forms.Form",
+ "Write-Host $form"
+ }));
+
+ await PsesDebugAdapterClient.LaunchScript(filePath, Started).ConfigureAwait(false);
+
+ var setBreakpointsResponse = await PsesDebugAdapterClient.SetFunctionBreakpoints(
+ new SetFunctionBreakpointsArguments
+ {
+ Breakpoints = new FunctionBreakpoint[]
+ {
+ new FunctionBreakpoint
+ {
+ Name = "Write-Host",
+ }
+ }
+ }).ConfigureAwait(false);
+
+ var breakpoint = setBreakpointsResponse.Breakpoints.First();
+ Assert.True(breakpoint.Verified);
+
+ ConfigurationDoneResponse configDoneResponse = await PsesDebugAdapterClient.RequestConfigurationDone(new ConfigurationDoneArguments()).ConfigureAwait(false);
+ Assert.NotNull(configDoneResponse);
+
+ // At this point the script should be running so lets give it time
+ await Task.Delay(2000).ConfigureAwait(false);
+
+ var variablesResponse = await PsesDebugAdapterClient.RequestVariables(
+ new VariablesArguments
+ {
+ VariablesReference = 1
+ }).ConfigureAwait(false);
+
+ var form = variablesResponse.Variables.FirstOrDefault(v => v.Name == "$form");
+ Assert.NotNull(form);
+ Assert.Equal("System.Windows.Forms.Form, Text: ", form.Value);
+ }
}
}
diff --git a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj
index 756ac8bd0..e7c907a00 100644
--- a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj
+++ b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj
@@ -10,8 +10,8 @@
-
-
+
+
diff --git a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
index b3cedbd14..8dd322d0a 100644
--- a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
@@ -32,6 +32,16 @@ public class DebugServiceTests : IDisposable
private AsyncQueue sessionStateQueue =
new AsyncQueue();
+ private ScriptFile GetDebugScript(string fileName)
+ {
+ return this.workspace.GetFile(
+ TestUtilities.NormalizePath(Path.Combine(
+ Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
+ "../../../../PowerShellEditorServices.Test.Shared/Debugging",
+ fileName
+ )));
+ }
+
public DebugServiceTests()
{
var logger = NullLogger.Instance;
@@ -41,18 +51,9 @@ public DebugServiceTests()
this.workspace = new WorkspaceService(NullLoggerFactory.Instance);
- // Load the test debug file
- this.debugScriptFile =
- this.workspace.GetFile(
- TestUtilities.NormalizePath(Path.Combine(
- Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
- "../../../../PowerShellEditorServices.Test.Shared/Debugging/VariableTest.ps1")));
-
- this.variableScriptFile =
- this.workspace.GetFile(
- TestUtilities.NormalizePath(Path.Combine(
- Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
- "../../../../PowerShellEditorServices.Test.Shared/Debugging/VariableTest.ps1")));
+ // Load the test debug files
+ this.debugScriptFile = GetDebugScript("DebugTest.ps1");
+ this.variableScriptFile = GetDebugScript("VariableTest.ps1");
this.debugService = new DebugService(
this.powerShellContext,
@@ -65,13 +66,6 @@ public DebugServiceTests()
this.debugService.DebuggerStopped += debugService_DebuggerStopped;
this.debugService.BreakpointUpdated += debugService_BreakpointUpdated;
-
- // Load the test debug file
- this.debugScriptFile =
- this.workspace.GetFile(
- TestUtilities.NormalizePath(Path.Combine(
- Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
- "../../../../PowerShellEditorServices.Test.Shared/Debugging/DebugTest.ps1")));
}
async void powerShellContext_SessionStateChanged(object sender, SessionStateChangedEventArgs e)
@@ -123,11 +117,7 @@ public async Task DebuggerAcceptsScriptArgs(string[] args)
// The path is intentionally odd (some escaped chars but not all) because we are testing
// the internal path escaping mechanism - it should escape certains chars ([, ] and space) but
// it should not escape already escaped chars.
- ScriptFile debugWithParamsFile =
- this.workspace.GetFile(
- TestUtilities.NormalizePath(Path.Combine(
- Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
- "../../../../PowerShellEditorServices.Test.Shared/Debugging/Debug W&ith Params [Test].ps1")));
+ ScriptFile debugWithParamsFile = GetDebugScript("Debug W&ith Params [Test].ps1");
await this.debugService.SetLineBreakpointsAsync(
debugWithParamsFile,
@@ -889,7 +879,7 @@ await this.debugService.SetLineBreakpointsAsync(
var nullStringVar = variables.FirstOrDefault(v => v.Name == "$nullString");
Assert.NotNull(nullStringVar);
- Assert.True("[NullString]".Equals(nullStringVar.ValueString));
+ Assert.Equal("[NullString]", nullStringVar.ValueString);
Assert.True(nullStringVar.IsExpandable);
// Abort script execution early and wait for completion
@@ -973,6 +963,7 @@ await this.debugService.SetLineBreakpointsAsync(
// Verifies fix for issue #86, $proc = Get-Process foo displays just the ETS property set
// and not all process properties.
+ [Trait("Category", "DebugService")]
[Fact]
public async Task DebuggerVariableProcessObjDisplaysCorrectly()
{
diff --git a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj
index 9c146f426..c801384ab 100644
--- a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj
+++ b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj
@@ -34,8 +34,7 @@
-
-
+