diff --git a/src/functions/Coverage.ps1 b/src/functions/Coverage.ps1
index 739ed90fc..781b9c331 100644
--- a/src/functions/Coverage.ps1
+++ b/src/functions/Coverage.ps1
@@ -249,7 +249,8 @@ function Get-CoverageBreakpoints {
[ScriptBlock]$Logger
)
- $fileGroups = @($CoverageInfo | & $SafeCommands['Group-Object'] -Property Path)
+ # PowerShell 6.1+ sorts by default in Group-Object. We need to sort for consistent output in Windows PowerShell
+ $fileGroups = @($CoverageInfo | & $SafeCommands['Group-Object'] -Property Path | & $SafeCommands['Sort-Object'] -Property Name)
foreach ($fileGroup in $fileGroups) {
if ($null -ne $Logger) {
$sw = [System.Diagnostics.Stopwatch]::StartNew()
@@ -287,9 +288,16 @@ function Get-CommandsInFile {
# In PowerShell 5.0, dynamic keywords for DSC configurations are represented by the DynamicKeywordStatementAst
# class. They still trigger breakpoints, but are not a child class of CommandBaseAst anymore.
+ # ReturnStatementAst is excluded as it's not behaving consistent.
+ # "return" is not hit in 5.1 but fixed in a later version. Using "return 123" we get hit on 123 but not return.
+ # See https://github.com/pester/Pester/issues/1465#issuecomment-604323645
$predicate = {
$args[0] -is [System.Management.Automation.Language.DynamicKeywordStatementAst] -or
- $args[0] -is [System.Management.Automation.Language.CommandBaseAst]
+ $args[0] -is [System.Management.Automation.Language.CommandBaseAst] -or
+ $args[0] -is [System.Management.Automation.Language.BreakStatementAst] -or
+ $args[0] -is [System.Management.Automation.Language.ContinueStatementAst] -or
+ $args[0] -is [System.Management.Automation.Language.ExitStatementAst] -or
+ $args[0] -is [System.Management.Automation.Language.ThrowStatementAst]
}
}
else {
@@ -551,6 +559,7 @@ function Get-CoverageCommandText {
$reportParentExtentTypes = @(
[System.Management.Automation.Language.ReturnStatementAst]
+ [System.Management.Automation.Language.ExitStatementAst]
[System.Management.Automation.Language.ThrowStatementAst]
[System.Management.Automation.Language.AssignmentStatementAst]
[System.Management.Automation.Language.IfStatementAst]
@@ -818,9 +827,10 @@ function Get-JaCoCoReportXml {
[long] $endTime = [System.DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
[long] $startTime = [math]::Floor($endTime - $TotalMilliseconds)
+ # PowerShell 6.1+ sorts by default in Group-Object. We need to sort for consistent output in Windows PowerShell
$folderGroups = $CommandCoverage | & $SafeCommands["Group-Object"] -Property {
& $SafeCommands["Split-Path"] $_.File -Parent
- }
+ } | & $SafeCommands["Sort-Object"] -Property Name
$packageList = [System.Collections.Generic.List[psobject]]@()
diff --git a/src/functions/TestResults.NUnit25.ps1 b/src/functions/TestResults.NUnit25.ps1
index aa0eec17a..a0b8f74ff 100644
--- a/src/functions/TestResults.NUnit25.ps1
+++ b/src/functions/TestResults.NUnit25.ps1
@@ -110,7 +110,8 @@ function Write-NUnitTestSuiteElements {
$suites = @(
# Tests only have GroupId if parameterized. All other tests are put in group with '' value
- $Node.Tests | & $SafeCommands['Group-Object'] -Property GroupId
+ # PowerShell 6.1+ sorts by default in Group-Object. We need to sort for consistent output in Windows PowerShell
+ $Node.Tests | & $SafeCommands['Group-Object'] -Property GroupId | & $SafeCommands["Sort-Object"] -Property Name
)
foreach ($suite in $suites) {
diff --git a/src/functions/TestResults.NUnit3.ps1 b/src/functions/TestResults.NUnit3.ps1
index 75db6f9cc..a4b08a70f 100644
--- a/src/functions/TestResults.NUnit3.ps1
+++ b/src/functions/TestResults.NUnit3.ps1
@@ -135,7 +135,8 @@ function Write-NUnit3TestSuiteElement {
$blockGroups = @(
# Blocks only have GroupId if parameterized (using -ForEach). All other blocks are put in group with '' value
- $Node.Blocks | & $SafeCommands['Group-Object'] -Property GroupId
+ # PowerShell 6.1+ sorts by default in Group-Object. We need to sort for consistent output in Windows PowerShell
+ $Node.Blocks | & $SafeCommands['Group-Object'] -Property GroupId | & $SafeCommands["Sort-Object"] -Property Name
)
foreach ($group in $blockGroups) {
@@ -170,7 +171,8 @@ function Write-NUnit3TestSuiteElement {
$testGroups = @(
# Tests only have GroupId if parameterized. All other tests are put in group with '' value
- $Node.Tests | & $SafeCommands['Group-Object'] -Property GroupId
+ # PowerShell 6.1+ sorts by default in Group-Object. We need to sort for consistent output in Windows PowerShell
+ $Node.Tests | & $SafeCommands['Group-Object'] -Property GroupId | & $SafeCommands["Sort-Object"] -Property Name
)
foreach ($group in $testGroups) {
diff --git a/tst/functions/Coverage.Tests.ps1 b/tst/functions/Coverage.Tests.ps1
index bcfa99ba0..b108745fb 100644
--- a/tst/functions/Coverage.Tests.ps1
+++ b/tst/functions/Coverage.Tests.ps1
@@ -17,6 +17,8 @@ InPesterModuleScope {
$testScriptPath = Join-Path -Path $root -ChildPath TestScript.ps1
$testScript2Path = Join-Path -Path $root -ChildPath TestScript2.ps1
$testScript3Path = Join-Path -Path $rootSubFolder -ChildPath TestScript3.ps1
+ $testScriptStatementsPath = Join-Path -Path $root -ChildPath TestScriptStatements.ps1
+ $testScriptExitPath = Join-Path -Path $root -ChildPath TestScriptExit.ps1
$null = New-Item -Path $testScriptPath -ItemType File -ErrorAction SilentlyContinue
@@ -42,7 +44,7 @@ InPesterModuleScope {
function FunctionTwo
{
- 'I am function two. I never get called.'
+ 'I am function two. I never get called.'
}
FunctionOne
@@ -133,6 +135,54 @@ InPesterModuleScope {
-f `
'other'
+'@
+
+ $null = New-Item -Path $testScriptStatementsPath -ItemType File -ErrorAction SilentlyContinue
+
+ Set-Content -Path $testScriptStatementsPath -Value @'
+ try {
+ try {
+ throw 'omg'
+ }
+ catch {
+ throw
+ }
+ }
+ catch { }
+
+ switch (1,2,3) {
+ 1 { continue; }
+ 2 { break }
+ 3 { 'I was skipped because 2 called break in switch.' }
+ }
+
+ :myBreakLabel foreach ($i in 1..100) {
+ foreach ($o in 1) {
+ break myBreakLabel
+ }
+ 'I was skipped by a labeled break.'
+ }
+
+ :myLoopLabel foreach ($i in 1) {
+ foreach ($o in 1..100) {
+ continue myLoopLabel
+ }
+ 'I was skipped by a labeled contiune.'
+ }
+
+ # These should not be included in code coverage
+ & { return }
+ & { return 123 }
+
+ # will exit the script
+ exit
+'@
+
+ $null = New-Item -Path $testScriptExitPath -ItemType File -ErrorAction SilentlyContinue
+
+ Set-Content -Path $testScriptExitPath -Value @'
+ # will exit the script, so keep in own file
+ exit 123
'@
}
@@ -143,14 +193,16 @@ InPesterModuleScope {
BeforeAll {
# TODO: renaming, breakpoints mean "code point of interests" in most cases here, not actual breakpoints
# Path deliberately duplicated to make sure the code doesn't produce multiple breakpoints for the same commands
- $breakpoints = Enter-CoverageAnalysis -CodeCoverage $testScriptPath, $testScriptPath, $testScript2Path, $testScript3Path -UseBreakpoints $UseBreakpoints
+ $breakpoints = Enter-CoverageAnalysis -CodeCoverage $testScriptPath, $testScriptPath, $testScript2Path, $testScript3Path, $testScriptStatementsPath, $testScriptExitPath -UseBreakpoints $UseBreakpoints
- @($breakpoints).Count | Should -Be 19 -Because 'it has the proper number of breakpoints defined'
+ @($breakpoints).Count | Should -Be 40 -Because 'it has the proper number of breakpoints defined'
$sb = {
$null = & $testScriptPath
$null = & $testScript2Path
$null = & $testScript3Path
+ $null = & $testScriptStatementsPath
+ $null = & $testScriptExitPath
}
if ($UseBreakpoints) {
@@ -167,29 +219,32 @@ InPesterModuleScope {
}
It 'Reports the proper number of executed commands' {
- $coverageReport.NumberOfCommandsExecuted | Should -Be 16
+ $coverageReport.NumberOfCommandsExecuted | Should -Be 34
}
It 'Reports the proper number of analyzed commands' {
- $coverageReport.NumberOfCommandsAnalyzed | Should -Be 19
+ $coverageReport.NumberOfCommandsAnalyzed | Should -Be 40
}
It 'Reports the proper number of analyzed files' {
- $coverageReport.NumberOfFilesAnalyzed | Should -Be 3
+ $coverageReport.NumberOfFilesAnalyzed | Should -Be 5
}
It 'Reports the proper number of missed commands' {
- $coverageReport.MissedCommands.Count | Should -Be 3
+ $coverageReport.MissedCommands.Count | Should -Be 6
}
It 'Reports the correct missed command' {
$coverageReport.MissedCommands[0].Command | Should -Be "'I cannot get called.'"
- $coverageReport.MissedCommands[1].Command | Should -Be "'I am function two. I never get called.'"
+ $coverageReport.MissedCommands[1].Command | Should -Be "'I am function two. I never get called.'"
$coverageReport.MissedCommands[2].Command | Should -Be "'I am method two. I never get called.'"
+ $coverageReport.MissedCommands[3].Command | Should -Be "'I was skipped because 2 called break in switch.'"
+ $coverageReport.MissedCommands[4].Command | Should -Be "'I was skipped by a labeled break.'"
+ $coverageReport.MissedCommands[5].Command | Should -Be "'I was skipped by a labeled contiune.'"
}
It 'Reports the proper number of hit commands' {
- $coverageReport.HitCommands.Count | Should -Be 16
+ $coverageReport.HitCommands.Count | Should -Be 34
}
It 'Reports the correct hit command' {
@@ -289,6 +344,28 @@ InPesterModuleScope {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -317,10 +394,40 @@ InPesterModuleScope {
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
')
}
@@ -429,6 +536,28 @@ InPesterModuleScope {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -457,10 +586,40 @@ InPesterModuleScope {
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -486,10 +645,10 @@ InPesterModuleScope {
-
-
-
-
+
+
+
+
')
}
@@ -503,13 +662,13 @@ InPesterModuleScope {
(Clear-WhiteSpace $coberturaReportXml) | Should -Be (Clear-WhiteSpace '
-
-
+
@@ -580,6 +739,36 @@ InPesterModuleScope {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -663,7 +852,7 @@ InPesterModuleScope {
}
It 'Reports the correct missed command' {
- $coverageReport.MissedCommands[0].Command | Should -Be "'I am function two. I never get called.'"
+ $coverageReport.MissedCommands[0].Command | Should -Be "'I am function two. I never get called.'"
}
It 'Reports the proper number of hit commands' {
@@ -814,7 +1003,7 @@ InPesterModuleScope {
It 'Reports the correct missed command' {
$coverageReport.MissedCommands[0].Command | Should -Be "'I cannot get called.'"
- $coverageReport.MissedCommands[1].Command | Should -Be "'I am function two. I never get called.'"
+ $coverageReport.MissedCommands[1].Command | Should -Be "'I am function two. I never get called.'"
}
It 'Reports the proper number of hit commands' {