Skip to content

Commit 5bb5b8a

Browse files
Merge pull request #1542 from PowerShell/andschwa/forms-test
Add regression test for `System.Windows.Forms` bug
2 parents 69a0b04 + cd29c49 commit 5bb5b8a

File tree

5 files changed

+80
-31
lines changed

5 files changed

+80
-31
lines changed

src/PowerShellEditorServices/PowerShellEditorServices.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
2929
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="5.0.0" />
3030
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
31-
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="0.19.2" />
32-
<PackageReference Include="OmniSharp.Extensions.DebugAdapter.Server" Version="0.19.2" />
31+
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="0.19.3" />
32+
<PackageReference Include="OmniSharp.Extensions.DebugAdapter.Server" Version="0.19.3" />
3333
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
3434
<PackageReference Include="Serilog" Version="2.10.0" />
3535
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />

test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs

+59
Original file line numberDiff line numberDiff line change
@@ -228,5 +228,64 @@ public async Task CanSetBreakpointsAsync()
228228
(i) => Assert.Equal("at breakpoint", i),
229229
(i) => Assert.Equal("after breakpoint", i));
230230
}
231+
232+
// This is a regression test for a bug where user code causes a new synchronization context
233+
// to be created, breaking the extension. It's most evident when debugging PowerShell
234+
// scripts that use System.Windows.Forms. It required fixing both Editor Services and
235+
// OmniSharp.
236+
//
237+
// This test depends on PowerShell being able to load System.Windows.Forms, which only works
238+
// reliably with Windows PowerShell. It works with PowerShell Core in the real-world;
239+
// however, our host executable is xUnit, not PowerShell. So by restricting to Windows
240+
// PowerShell, we avoid all issues with our test project (and the xUnit executable) not
241+
// having System.Windows.Forms deployed, and can instead rely on the Windows Global Assembly
242+
// Cache (GAC) to find it.
243+
[Trait("Category", "DAP")]
244+
[SkippableFact]
245+
public async Task CanStepPastSystemWindowsForms()
246+
{
247+
Skip.IfNot(PsesStdioProcess.IsWindowsPowerShell);
248+
Skip.If(PsesStdioProcess.RunningInConstainedLanguageMode);
249+
250+
string filePath = NewTestFile(string.Join(Environment.NewLine, new []
251+
{
252+
"Add-Type -AssemblyName System.Windows.Forms",
253+
"$form = New-Object System.Windows.Forms.Form",
254+
"Write-Host $form"
255+
}));
256+
257+
await PsesDebugAdapterClient.LaunchScript(filePath, Started).ConfigureAwait(false);
258+
259+
var setBreakpointsResponse = await PsesDebugAdapterClient.SetFunctionBreakpoints(
260+
new SetFunctionBreakpointsArguments
261+
{
262+
Breakpoints = new FunctionBreakpoint[]
263+
{
264+
new FunctionBreakpoint
265+
{
266+
Name = "Write-Host",
267+
}
268+
}
269+
}).ConfigureAwait(false);
270+
271+
var breakpoint = setBreakpointsResponse.Breakpoints.First();
272+
Assert.True(breakpoint.Verified);
273+
274+
ConfigurationDoneResponse configDoneResponse = await PsesDebugAdapterClient.RequestConfigurationDone(new ConfigurationDoneArguments()).ConfigureAwait(false);
275+
Assert.NotNull(configDoneResponse);
276+
277+
// At this point the script should be running so lets give it time
278+
await Task.Delay(2000).ConfigureAwait(false);
279+
280+
var variablesResponse = await PsesDebugAdapterClient.RequestVariables(
281+
new VariablesArguments
282+
{
283+
VariablesReference = 1
284+
}).ConfigureAwait(false);
285+
286+
var form = variablesResponse.Variables.FirstOrDefault(v => v.Name == "$form");
287+
Assert.NotNull(form);
288+
Assert.Equal("System.Windows.Forms.Form, Text: ", form.Value);
289+
}
231290
}
232291
}

test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
1111
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
1212
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
13-
<PackageReference Include="OmniSharp.Extensions.LanguageClient" Version="0.19.2" />
14-
<PackageReference Include="OmniSharp.Extensions.DebugAdapter.Client" Version="0.19.2" />
13+
<PackageReference Include="OmniSharp.Extensions.LanguageClient" Version="0.19.3" />
14+
<PackageReference Include="OmniSharp.Extensions.DebugAdapter.Client" Version="0.19.3" />
1515
<PackageReference Include="xunit" Version="2.4.1" />
1616
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
1717
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />

test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs

+16-25
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ public class DebugServiceTests : IDisposable
3232
private AsyncQueue<SessionStateChangedEventArgs> sessionStateQueue =
3333
new AsyncQueue<SessionStateChangedEventArgs>();
3434

35+
private ScriptFile GetDebugScript(string fileName)
36+
{
37+
return this.workspace.GetFile(
38+
TestUtilities.NormalizePath(Path.Combine(
39+
Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
40+
"../../../../PowerShellEditorServices.Test.Shared/Debugging",
41+
fileName
42+
)));
43+
}
44+
3545
public DebugServiceTests()
3646
{
3747
var logger = NullLogger.Instance;
@@ -41,18 +51,9 @@ public DebugServiceTests()
4151

4252
this.workspace = new WorkspaceService(NullLoggerFactory.Instance);
4353

44-
// Load the test debug file
45-
this.debugScriptFile =
46-
this.workspace.GetFile(
47-
TestUtilities.NormalizePath(Path.Combine(
48-
Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
49-
"../../../../PowerShellEditorServices.Test.Shared/Debugging/VariableTest.ps1")));
50-
51-
this.variableScriptFile =
52-
this.workspace.GetFile(
53-
TestUtilities.NormalizePath(Path.Combine(
54-
Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
55-
"../../../../PowerShellEditorServices.Test.Shared/Debugging/VariableTest.ps1")));
54+
// Load the test debug files
55+
this.debugScriptFile = GetDebugScript("DebugTest.ps1");
56+
this.variableScriptFile = GetDebugScript("VariableTest.ps1");
5657

5758
this.debugService = new DebugService(
5859
this.powerShellContext,
@@ -65,13 +66,6 @@ public DebugServiceTests()
6566

6667
this.debugService.DebuggerStopped += debugService_DebuggerStopped;
6768
this.debugService.BreakpointUpdated += debugService_BreakpointUpdated;
68-
69-
// Load the test debug file
70-
this.debugScriptFile =
71-
this.workspace.GetFile(
72-
TestUtilities.NormalizePath(Path.Combine(
73-
Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
74-
"../../../../PowerShellEditorServices.Test.Shared/Debugging/DebugTest.ps1")));
7569
}
7670

7771
async void powerShellContext_SessionStateChanged(object sender, SessionStateChangedEventArgs e)
@@ -123,11 +117,7 @@ public async Task DebuggerAcceptsScriptArgs(string[] args)
123117
// The path is intentionally odd (some escaped chars but not all) because we are testing
124118
// the internal path escaping mechanism - it should escape certains chars ([, ] and space) but
125119
// it should not escape already escaped chars.
126-
ScriptFile debugWithParamsFile =
127-
this.workspace.GetFile(
128-
TestUtilities.NormalizePath(Path.Combine(
129-
Path.GetDirectoryName(typeof(DebugServiceTests).Assembly.Location),
130-
"../../../../PowerShellEditorServices.Test.Shared/Debugging/Debug W&ith Params [Test].ps1")));
120+
ScriptFile debugWithParamsFile = GetDebugScript("Debug W&ith Params [Test].ps1");
131121

132122
await this.debugService.SetLineBreakpointsAsync(
133123
debugWithParamsFile,
@@ -889,7 +879,7 @@ await this.debugService.SetLineBreakpointsAsync(
889879

890880
var nullStringVar = variables.FirstOrDefault(v => v.Name == "$nullString");
891881
Assert.NotNull(nullStringVar);
892-
Assert.True("[NullString]".Equals(nullStringVar.ValueString));
882+
Assert.Equal("[NullString]", nullStringVar.ValueString);
893883
Assert.True(nullStringVar.IsExpandable);
894884

895885
// Abort script execution early and wait for completion
@@ -973,6 +963,7 @@ await this.debugService.SetLineBreakpointsAsync(
973963

974964
// Verifies fix for issue #86, $proc = Get-Process foo displays just the ETS property set
975965
// and not all process properties.
966+
[Trait("Category", "DebugService")]
976967
[Fact]
977968
public async Task DebuggerVariableProcessObjDisplaysCorrectly()
978969
{

test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj

+1-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
<PackageReference Include="xunit" Version="2.4.1" />
3535
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
3636
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
37-
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="0.19.2" />
38-
<DotNetCliToolReference Include="dotnet-xunit" Version="2.4.0-beta.1.build3958" />
37+
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="0.19.3" />
3938
</ItemGroup>
4039

4140
<ItemGroup>

0 commit comments

Comments
 (0)