Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,7 +62,7 @@
that passed before may now correctly fail.
- [**#96**](https://github.com/psake/PowerShellBuild/issues/96)
`Test-PSBuildScriptAnalysis` no longer fails with a path-resolution error
when `SettingsPath` is not supplied. An unsupplied path was forwarded to

Check warning on line 65 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions/ CI / Run Linters

Unknown word (unsupplied) Suggestions: (unapplied, unsullied, unspoiled, unstapled, unsupported)
PSScriptAnalyzer as `-Settings ''`, which resolved against the current
directory and threw before any analysis ran, so the function's own
documented example could not run as written.
Expand All@@ -76,6 +76,15 @@
two Pester versions were installed side by side. When no Pester is loaded,
the newest installed version (5.0.0 minimum) is imported as before, and a
loaded Pester older than 5.0.0 now produces a clear error.
- [**#138**](https://github.com/psake/PowerShellBuild/issues/138)
`Test-PSBuildPester` now reports real code coverage percentages and compares
them against `CodeCoverageThreshold` correctly. Each percentage was passed
through `[Math]::Truncate`, which collapses any fraction to zero, so the
coverage report always printed `0.00%` (or `100.00%`) and every threshold
above zero failed the build unless coverage was exactly 100%. Consumers who
set `$PSBPreference.Test.CodeCoverage.Threshold` could not use coverage
gating at all. The comparison is now strictly more permissive than before,
so a build that passed with a coverage threshold set still passes.

## [0.8.2] 2026-07-08

Expand Down
7 changes: 6 additions & 1 deletion PowerShellBuild/Public/Test-PSBuildPester.ps1
Original file line numberDiff line numberDiff line change
Expand Up@@ -124,7 +124,12 @@ function Test-PSBuildPester {
[xml]$testCoverage = Get-Content $CodeCoverageOutputFile
$ccReport = $testCoverage.report.counter.ForEach({
$total = [int]$_.missed + [int]$_.covered
$percent = [Math]::Truncate([int]$_.covered / $total)
# Keep the ratio as a fraction between 0 and 1. [Math]::Truncate collapsed
# every partial result to 0, which both printed 0.00% and failed the
# CodeCoverageThreshold comparison below for any coverage under 100%.
# The value is deliberately not rounded: rounding 0.7996 up to 0.80 would
# pass a 0.80 threshold that the real coverage does not meet.
$percent = [int]$_.covered / $total
[PSCustomObject]@{
name = $textInfo.ToTitleCase($_.Type.ToLower())
percent = $percent
Expand Down
40 changes: 39 additions & 1 deletion tests/Test-PSBuildPester.tests.ps1
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,8 +61,12 @@

$threw = $false
$errorMessage = $null
# Capture the command's output rather than letting it fall through to the job's
# output stream, where the coverage report lines would be interleaved with the
# result object below.
$commandOutput = @()
try {
Test-PSBuildPester @testPSBuildPesterParameters
$commandOutput = @(Test-PSBuildPester @testPSBuildPesterParameters)
} catch {
$threw = $true
$errorMessage = $_.Exception.Message
Expand All@@ -71,6 +75,7 @@
[PSCustomObject]@{
Threw = $threw
ErrorMessage = $errorMessage
Output = $commandOutput
LoadedPesterVersions = @((Get-Module -Name 'Pester').Version.ToString())
}
} -ArgumentList $InnerPesterVersion, $script:builtModulePath, $Path, $AdditionalParameters
Expand All@@ -82,9 +87,9 @@

# Scenario directories, generated at runtime.
$script:healthyPath = Join-Path -Path $TestDrive -ChildPath 'healthy'
$script:failingTestPath = Join-Path -Path $TestDrive -ChildPath 'failingtest'

Check warning on line 90 in tests/Test-PSBuildPester.tests.ps1

View workflow job for this annotation

GitHub Actions/ CI / Run Linters

Unknown word (failingtest) Suggestions: (failings, faintest, failing's)
$script:beforeAllCrashPath = Join-Path -Path $TestDrive -ChildPath 'beforeallcrash'

Check warning on line 91 in tests/Test-PSBuildPester.tests.ps1

View workflow job for this annotation

GitHub Actions/ CI / Run Linters

Unknown word (beforeallcrash)
$script:discoveryCrashPath = Join-Path -Path $TestDrive -ChildPath 'discoverycrash'

Check warning on line 92 in tests/Test-PSBuildPester.tests.ps1

View workflow job for this annotation

GitHub Actions/ CI / Run Linters

Unknown word (discoverycrash)
$script:coveragePath = Join-Path -Path $TestDrive -ChildPath 'coverage'
$script:outputPath = Join-Path -Path $TestDrive -ChildPath 'out'
foreach ($directory in @(
Expand DownExpand Up@@ -220,6 +225,39 @@
[xml]$coverageReport = Get-Content -Path $coverageOutputPath -Raw
$coverageReport.report | Should -Not -BeNullOrEmpty
}

# The coverage scenario exercises only Get-Widget while measuring both public fixture
# functions, so measured coverage is always partial: comfortably above 1% and well
# below 99%. Asserting from both sides pins the reported value to a fraction between
# 0 and 1 -- a truncated 0 fails the first test, and a 0-to-100 scale fails the second.
It 'passes when measured coverage is above the code coverage threshold' {
# Regression: #138
$coverageOutputPath = Join-Path -Path $script:outputPath -ChildPath "coverage-above-threshold-$script:innerVersion.xml"
$additionalParameters = @{
CodeCoverage = $true
CodeCoverageFiles = @(Join-Path -Path $script:fixturePath -ChildPath 'Public/*.ps1')
CodeCoverageOutputFile = $coverageOutputPath
CodeCoverageThreshold = 0.01
}
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:coveragePath -AdditionalParameters $additionalParameters

$result.Threw | Should -BeFalse
}

It 'fails when measured coverage is below the code coverage threshold' {
# Regression: #138
$coverageOutputPath = Join-Path -Path $script:outputPath -ChildPath "coverage-below-threshold-$script:innerVersion.xml"
$additionalParameters = @{
CodeCoverage = $true
CodeCoverageFiles = @(Join-Path -Path $script:fixturePath -ChildPath 'Public/*.ps1')
CodeCoverageOutputFile = $coverageOutputPath
CodeCoverageThreshold = 0.99
}
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:coveragePath -AdditionalParameters $additionalParameters

$result.Threw | Should -BeTrue
$result.ErrorMessage | Should -Match 'less than the threshold'
}
}

# BeforeDiscovery variables are not visible during the run phase, so the discovered version
Expand Down
Loading