mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Fix sequence point update for switch/if/for/while/do-while/do-until statements (#7305)
- Make switch-statement report correct error position when it fails to evaluate the condition. - Make for-statement report correct error position when it fails to evaluate the initializer. - For the condition of `if/for/while/do-while/do-until` statements, the sequence point update is either duplicate in some cases (for `if/for/while`) which causes debugger to stop at the condition twice before moving forward, or missing (for `do-while/do-until`) which causes debugger to skip the condition. They are fixed.
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
$script1 = @'
|
||||
|
||||
Describe "Breakpoints when set should be hit" -tag "CI" {
|
||||
Context "Basic tests" {
|
||||
BeforeAll {
|
||||
$script = @'
|
||||
'aaa'.ToString() > $null
|
||||
'aa' > $null
|
||||
"a" 2> $null | ForEach-Object { $_ }
|
||||
@@ -8,32 +12,285 @@ $script1 = @'
|
||||
'bb'.ToSTring() > $null
|
||||
'bbb'
|
||||
'@
|
||||
$script2 = @'
|
||||
"line 1"
|
||||
"line 2"
|
||||
"line 3"
|
||||
$path = Setup -PassThru -File BasicTest.ps1 -Content $script
|
||||
$bps = 1..6 | ForEach-Object { set-psbreakpoint -script $path -line $_ -Action { continue } }
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
$bps | Remove-PSBreakPoint
|
||||
}
|
||||
|
||||
It "A redirected breakpoint is hit" {
|
||||
& $path
|
||||
foreach ( $bp in $bps ) {
|
||||
$bp.HitCount | Should -Be 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "Break point on switch condition should be hit only when enumerating it" {
|
||||
BeforeAll {
|
||||
$script = @'
|
||||
$test = 1..2
|
||||
switch ($test)
|
||||
{
|
||||
default {}
|
||||
}
|
||||
'@
|
||||
$path = Setup -PassThru -File SwitchScript.ps1 -Content $script
|
||||
$breakpoint = Set-PSBreakpoint -Script $path -Line 2 -Action { continue }
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Remove-PSBreakpoint -Breakpoint $breakpoint
|
||||
}
|
||||
|
||||
It "switch condition should be hit 3 times" {
|
||||
## MoveNext() will be called on the condition for 3 times
|
||||
$null = & $path
|
||||
$breakpoint.HitCount | Should -Be 3
|
||||
}
|
||||
}
|
||||
|
||||
Context "Break point on for-statement initializer should be hit" {
|
||||
BeforeAll {
|
||||
$for_script_1 = @'
|
||||
$test = 2
|
||||
for ("string".Length;
|
||||
$test -gt 0; $test--) { }
|
||||
'@
|
||||
|
||||
Describe "Breakpoints when set should be hit" -tag "CI" {
|
||||
BeforeAll {
|
||||
$path = setup -pass -f TestScript_1.ps1 -content $script1
|
||||
$bps = 1..6 | ForEach-Object { set-psbreakpoint -script $path -line $_ -Action { continue } }
|
||||
$for_script_2 = @'
|
||||
$test = $PSCommandPath
|
||||
for (Test-Path $test;
|
||||
$test -eq "blah";) { }
|
||||
'@
|
||||
|
||||
$for_script_3 = @'
|
||||
for ($test = 2;
|
||||
$test -gt 0; $test--) { }
|
||||
'@
|
||||
|
||||
$for_script_4 = @'
|
||||
$test = 2
|
||||
for (;$test -gt 0;
|
||||
$test--) { }
|
||||
'@
|
||||
|
||||
$for_script_5 = @'
|
||||
$test = $PSCommandPath
|
||||
for (;Test-Path $test;)
|
||||
{
|
||||
$test = "blah"
|
||||
}
|
||||
'@
|
||||
$ForScript_1 = Setup -PassThru -File ForScript_1.ps1 -Content $for_script_1
|
||||
$bp_1 = Set-PSBreakpoint -Script $ForScript_1 -Line 2 -Action { continue }
|
||||
|
||||
$ForScript_2 = Setup -PassThru -File ForScript_2.ps1 -Content $for_script_2
|
||||
$bp_2 = Set-PSBreakpoint -Script $ForScript_2 -Line 2 -Action { continue }
|
||||
|
||||
$ForScript_3 = Setup -PassThru -File ForScript_3.ps1 -Content $for_script_3
|
||||
$bp_3 = Set-PSBreakpoint -Script $ForScript_3 -Line 1 -Action { continue }
|
||||
|
||||
$ForScript_4 = Setup -PassThru -File ForScript_4.ps1 -Content $for_script_4
|
||||
$bp_4 = Set-PSBreakpoint -Script $ForScript_4 -Line 2 -Action { continue }
|
||||
|
||||
$ForScript_5 = Setup -PassThru -File ForScript_5.ps1 -Content $for_script_5
|
||||
$bp_5 = Set-PSBreakpoint -Script $ForScript_5 -Line 2 -Action { continue }
|
||||
|
||||
$testCases = @(
|
||||
@{ Name = "expression initializer should be hit once"; Path = $ForScript_1; Breakpoint = $bp_1; HitCount = 1 }
|
||||
@{ Name = "pipeline initializer should be hit once"; Path = $ForScript_2; Breakpoint = $bp_2; HitCount = 1 }
|
||||
@{ Name = "assignment initializer should be hit 3 times"; Path = $ForScript_3; Breakpoint = $bp_3; HitCount = 1 }
|
||||
@{ Name = "pipeline condition should be hit 3 times"; Path = $ForScript_4; Breakpoint = $bp_4; HitCount = 3 }
|
||||
@{ Name = "pipeline condition should be hit 2 times"; Path = $ForScript_5; Breakpoint = $bp_5; HitCount = 2 }
|
||||
)
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Get-PSBreakpoint -Script $ForScript_1, $ForScript_2, $ForScript_3, $ForScript_4, $ForScript_5 | Remove-PSBreakpoint
|
||||
}
|
||||
|
||||
It "for-statement <Name>" -TestCases $testCases {
|
||||
param($Path, $Breakpoint, $HitCount)
|
||||
$null = & $Path
|
||||
$Breakpoint.HitCount | Should -Be $HitCount
|
||||
}
|
||||
}
|
||||
AfterAll {
|
||||
$bps | Remove-PSBreakPoint
|
||||
|
||||
Context "Break point on while loop condition should be hit" {
|
||||
BeforeAll {
|
||||
$while_script_1 = @'
|
||||
$test = "string"
|
||||
while ($test.Contains("str"))
|
||||
{
|
||||
$test = "blah"
|
||||
}
|
||||
'@
|
||||
|
||||
$while_script_2 = @'
|
||||
$test = $PSCommandPath
|
||||
while (Test-Path $test)
|
||||
{
|
||||
$test = "blah"
|
||||
}
|
||||
'@
|
||||
$WhileScript_1 = Setup -PassThru -File WhileScript_1.ps1 -Content $while_script_1
|
||||
$bp_1 = Set-PSBreakpoint -Script $WhileScript_1 -Line 2 -Action { continue }
|
||||
|
||||
$WhileScript_2 = Setup -PassThru -File WhileScript_2.ps1 -Content $while_script_2
|
||||
$bp_2 = Set-PSBreakpoint -Script $WhileScript_2 -Line 2 -Action { continue }
|
||||
|
||||
$testCases = @(
|
||||
@{ Name = "expression condition should be hit 2 times"; Path = $WhileScript_1; Breakpoint = $bp_1; HitCount = 2 }
|
||||
@{ Name = "pipeline condition should be hit 2 times"; Path = $WhileScript_2; Breakpoint = $bp_2; HitCount = 2 }
|
||||
)
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Get-PSBreakpoint -Script $WhileScript_1, $WhileScript_2 | Remove-PSBreakpoint
|
||||
}
|
||||
|
||||
It "while loop <Name>" -TestCases $testCases {
|
||||
param($Path, $Breakpoint, $HitCount)
|
||||
$null = & $Path
|
||||
$Breakpoint.HitCount | Should -Be $HitCount
|
||||
}
|
||||
}
|
||||
It "A redirected breakpoint is hit" {
|
||||
& $path
|
||||
foreach ( $bp in $bps ) {
|
||||
$bp.HitCount | Should -Be 1
|
||||
|
||||
Context "Break point on do-while loop condition should be hit" {
|
||||
BeforeAll {
|
||||
$do_while_script_1 = @'
|
||||
$test = "blah"
|
||||
do { echo $test }
|
||||
while ($test.Contains("str"))
|
||||
'@
|
||||
|
||||
$do_while_script_2 = @'
|
||||
$test = "blah"
|
||||
do { echo $test }
|
||||
while (Test-Path $test)
|
||||
'@
|
||||
$DoWhileScript_1 = Setup -PassThru -File DoWhileScript_1.ps1 -Content $do_while_script_1
|
||||
$bp_1 = Set-PSBreakpoint -Script $DoWhileScript_1 -Line 2 -Action { continue }
|
||||
|
||||
$DoWhileScript_2 = Setup -PassThru -File DoWhileScript_2.ps1 -Content $do_while_script_2
|
||||
$bp_2 = Set-PSBreakpoint -Script $DoWhileScript_2 -Line 2 -Action { continue }
|
||||
|
||||
$testCases = @(
|
||||
@{ Name = "expression condition should be hit 2 times"; Path = $DoWhileScript_1; Breakpoint = $bp_1; HitCount = 1 }
|
||||
@{ Name = "pipeline condition should be hit 2 times"; Path = $DoWhileScript_2; Breakpoint = $bp_2; HitCount = 1 }
|
||||
)
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Get-PSBreakpoint -Script $DoWhileScript_1, $DoWhileScript_2 | Remove-PSBreakpoint
|
||||
}
|
||||
|
||||
It "Do-While loop <Name>" -TestCases $testCases {
|
||||
param($Path, $Breakpoint, $HitCount)
|
||||
$null = & $Path
|
||||
$Breakpoint.HitCount | Should -Be $HitCount
|
||||
}
|
||||
}
|
||||
|
||||
Context "Break point on do-until loop condition should be hit" {
|
||||
BeforeAll {
|
||||
$do_until_script_1 = @'
|
||||
$test = "blah"
|
||||
do { echo $test }
|
||||
until ($test.Contains("bl"))
|
||||
'@
|
||||
|
||||
$do_until_script_2 = @'
|
||||
$test = $PSCommandPath
|
||||
do { echo $test }
|
||||
until (Test-Path $test)
|
||||
'@
|
||||
$DoUntilScript_1 = Setup -PassThru -File DoUntilScript_1.ps1 -Content $do_until_script_1
|
||||
$bp_1 = Set-PSBreakpoint -Script $DoUntilScript_1 -Line 2 -Action { continue }
|
||||
|
||||
$DoUntilScript_2 = Setup -PassThru -File DoUntilScript_2.ps1 -Content $do_until_script_2
|
||||
$bp_2 = Set-PSBreakpoint -Script $DoUntilScript_2 -Line 2 -Action { continue }
|
||||
|
||||
$testCases = @(
|
||||
@{ Name = "expression condition should be hit 2 times"; Path = $DoUntilScript_1; Breakpoint = $bp_1; HitCount = 1 }
|
||||
@{ Name = "pipeline condition should be hit 2 times"; Path = $DoUntilScript_2; Breakpoint = $bp_2; HitCount = 1 }
|
||||
)
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Get-PSBreakpoint -Script $DoUntilScript_1, $DoUntilScript_2 | Remove-PSBreakpoint
|
||||
}
|
||||
|
||||
It "Do-Until loop <Name>" -TestCases $testCases {
|
||||
param($Path, $Breakpoint, $HitCount)
|
||||
$null = & $Path
|
||||
$Breakpoint.HitCount | Should -Be $HitCount
|
||||
}
|
||||
}
|
||||
|
||||
Context "Break point on if condition should be hit" {
|
||||
BeforeAll {
|
||||
$if_script_1 = @'
|
||||
if ("string".Contains('str'))
|
||||
{ }
|
||||
'@
|
||||
$if_script_2 = @'
|
||||
if (Test-Path $PSCommandPath)
|
||||
{ }
|
||||
'@
|
||||
$if_script_3 = @'
|
||||
if ($false) {}
|
||||
elseif ("string".Contains('str'))
|
||||
{ }
|
||||
'@
|
||||
$if_script_4 = @'
|
||||
if ($false) {}
|
||||
elseif (Test-Path $PSCommandPath)
|
||||
{ }
|
||||
'@
|
||||
$IfScript_1 = Setup -PassThru -File IfScript_1.ps1 -Content $if_script_1
|
||||
$bp_1 = Set-PSBreakpoint -Script $IfScript_1 -Line 1 -Action { continue }
|
||||
|
||||
$IfScript_2 = Setup -PassThru -File IfScript_2.ps1 -Content $if_script_2
|
||||
$bp_2 = Set-PSBreakpoint -Script $IfScript_2 -Line 1 -Action { continue }
|
||||
|
||||
$IfScript_3 = Setup -PassThru -File IfScript_3.ps1 -Content $if_script_3
|
||||
$bp_3 = Set-PSBreakpoint -Script $IfScript_3 -Line 2 -Action { continue }
|
||||
|
||||
$IfScript_4 = Setup -PassThru -File IfScript_4.ps1 -Content $if_script_4
|
||||
$bp_4 = Set-PSBreakpoint -Script $IfScript_4 -Line 2 -Action { continue }
|
||||
|
||||
$testCases = @(
|
||||
@{ Name = "expression if-condition should be hit once"; Path = $IfScript_1; Breakpoint = $bp_1; HitCount = 1 }
|
||||
@{ Name = "pipeline if-condition should be hit once"; Path = $IfScript_2; Breakpoint = $bp_2; HitCount = 1 }
|
||||
@{ Name = "expression elseif-condition should be hit once"; Path = $IfScript_3; Breakpoint = $bp_3; HitCount = 1 }
|
||||
@{ Name = "pipeline elseif-condition should be hit once"; Path = $IfScript_4; Breakpoint = $bp_4; HitCount = 1 }
|
||||
)
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Get-PSBreakpoint -Script $IfScript_1, $IfScript_2, $IfScript_3, $IfScript_4 | Remove-PSBreakpoint
|
||||
}
|
||||
|
||||
It "If statement <Name>" -TestCases $testCases {
|
||||
param($Path, $Breakpoint, $HitCount)
|
||||
$null = & $Path
|
||||
$Breakpoint.HitCount | Should -Be $HitCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "It should be possible to reset runspace debugging" -tag "Feature" {
|
||||
BeforeAll {
|
||||
$path = setup -pass -f TestScript_2.ps1 -content $script2
|
||||
$scriptPath = "$testdrive/TestScript_2.ps1"
|
||||
$script = @'
|
||||
"line 1"
|
||||
"line 2"
|
||||
"line 3"
|
||||
'@
|
||||
$scriptPath = Setup -PassThru -File TestScript.ps1 -Content $script
|
||||
$iss = [initialsessionstate]::CreateDefault2();
|
||||
$rs = [runspacefactory]::CreateRunspace($iss)
|
||||
$rs.Name = "TestRunspaceDebuggerReset"
|
||||
@@ -87,6 +344,6 @@ Describe "It should be possible to reset runspace debugging" -tag "Feature" {
|
||||
}
|
||||
It "The script should run without a break" {
|
||||
$ps.Commands.Clear()
|
||||
$ps.addscript("$testdrive/TestScript_2.ps1").Invoke().Count | Should -Be 3
|
||||
$ps.addscript($scriptPath).Invoke().Count | Should -Be 3
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user