Tests/Tests-All.ps1
|
<# .SYNOPSIS Master test runner for PSWriteColorEX module using Pester V5 .DESCRIPTION This script runs all Pester tests for the PSWriteColorEX module with proper configuration for CI/CD pipelines including GitHub Actions. It generates test results in multiple formats and provides code coverage metrics. .PARAMETER OutputFormat Format for test results. Options: NUnitXml, JUnitXml, NUnit2.5, or NUnit3 Default: NUnitXml (compatible with most CI/CD systems) .PARAMETER OutputFile Path to save test results. Default: TestResults.xml .PARAMETER CodeCoverage Enable code coverage analysis. Default: $true .PARAMETER CodeCoverageOutputFile Path to save code coverage results. Default: Coverage.xml .PARAMETER MinimumCoverage Minimum code coverage percentage required (0-100). Default: 0 (no minimum) .PARAMETER ExcludePath Array of paths to exclude from code coverage analysis .PARAMETER PassThru Return the Pester result object .PARAMETER Show Control Pester output verbosity. Options: None, Normal, Detailed, Diagnostic Default: Normal .EXAMPLE .\Tests-All.ps1 .EXAMPLE .\Tests-All.ps1 -CodeCoverage -MinimumCoverage 70 .EXAMPLE .\Tests-All.ps1 -OutputFormat JUnitXml -OutputFile junit-results.xml .EXAMPLE .\Tests-All.ps1 -Show Detailed -PassThru .NOTES Requires Pester v5.0.0 or higher Compatible with PowerShell 5.1+ and PowerShell Core 6+ #> [CmdletBinding()] param( [ValidateSet('NUnitXml', 'JUnitXml', 'NUnit2.5', 'NUnit3')] [string]$OutputFormat = 'NUnitXml', [string]$OutputFile = 'TestResults.xml', [switch]$CodeCoverage = $true, [string]$CodeCoverageOutputFile = 'Coverage.xml', [ValidateRange(0, 100)] [int]$MinimumCoverage = 0, [string[]]$ExcludePath = @(), [switch]$PassThru, [ValidateSet('None', 'Normal', 'Detailed', 'Diagnostic')] [string]$Show = 'Normal' ) # Ensure we're using Pester v5 $requiredPesterVersion = [version]'5.0.0' $pesterModule = Get-Module -Name Pester -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1 if (-not $pesterModule -or $pesterModule.Version -lt $requiredPesterVersion) { Write-Host "Pester v5.0.0+ not found. Installing..." -ForegroundColor Yellow try { Install-Module -Name Pester -MinimumVersion 5.0.0 -Force -SkipPublisherCheck -Scope CurrentUser -ErrorAction Stop Write-Host "Pester v5 installed successfully" -ForegroundColor Green $pesterModule = Get-Module -Name Pester -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1 } catch { Write-Error "Failed to install Pester v5: $_" Write-Error "Please install manually: Install-Module -Name Pester -MinimumVersion 5.0.0 -Force -SkipPublisherCheck" exit 1 } } # Import Pester Import-Module Pester -MinimumVersion 5.0.0 -Force Write-Host "========================================" -ForegroundColor Cyan Write-Host " PSWriteColorEX Test Suite Runner" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" Write-Host "Pester Version: " -NoNewline Write-Host $pesterModule.Version -ForegroundColor Green Write-Host "PowerShell Version: " -NoNewline Write-Host $PSVersionTable.PSVersion -ForegroundColor Green Write-Host "Operating System: " -NoNewline Write-Host $PSVersionTable.OS -ForegroundColor Green Write-Host "" # Get module root and test paths $moduleRoot = Split-Path -Parent $PSScriptRoot $testRoot = $PSScriptRoot # Define all test files $testFiles = @( 'Tests-PSColorStyle.ps1' 'Tests-TestAnsiSupport.ps1' 'Tests-ConvertColorValue.ps1' 'Tests-NewGradientColorArray.ps1' 'Tests-WriteColorHelpers.ps1' 'Tests-WriteColorEX.ps1' 'Tests-WriteColorEXAutoPad.ps1' ) # Verify all test files exist $missingTests = @() foreach ($testFile in $testFiles) { $testPath = Join-Path $testRoot $testFile if (-not (Test-Path $testPath)) { $missingTests += $testFile } } if ($missingTests.Count -gt 0) { Write-Warning "The following test files are missing:" $missingTests | ForEach-Object { Write-Warning " - $_" } Write-Warning "Continuing with available tests..." } # Get all existing test files $existingTestFiles = $testFiles | Where-Object { Test-Path (Join-Path $testRoot $_) } | ForEach-Object { Join-Path $testRoot $_ } Write-Host "Running tests from $($existingTestFiles.Count) test files:" -ForegroundColor Yellow $existingTestFiles | ForEach-Object { Write-Host " - $(Split-Path $_ -Leaf)" -ForegroundColor Gray } Write-Host "" # Define code coverage paths $codeCoveragePaths = @( "$moduleRoot\Classes\*.ps1" "$moduleRoot\Private\*.ps1" "$moduleRoot\Public\*.ps1" "$moduleRoot\PSWriteColorEX.psm1" ) # Filter out excluded paths if ($ExcludePath.Count -gt 0) { $codeCoveragePaths = $codeCoveragePaths | Where-Object { $path = $_ $excluded = $false foreach ($exclude in $ExcludePath) { if ($path -like "*$exclude*") { $excluded = $true break } } -not $excluded } } # Create Pester configuration $pesterConfig = New-PesterConfiguration # Run configuration $pesterConfig.Run.Path = $existingTestFiles $pesterConfig.Run.PassThru = $true $pesterConfig.Run.Exit = $false # Output configuration $pesterConfig.Output.Verbosity = $Show # TestResult configuration $pesterConfig.TestResult.Enabled = $true $pesterConfig.TestResult.OutputFormat = $OutputFormat $pesterConfig.TestResult.OutputPath = $OutputFile # CodeCoverage configuration if ($CodeCoverage) { $pesterConfig.CodeCoverage.Enabled = $true $pesterConfig.CodeCoverage.Path = $codeCoveragePaths $pesterConfig.CodeCoverage.OutputFormat = 'JaCoCo' $pesterConfig.CodeCoverage.OutputPath = $CodeCoverageOutputFile $pesterConfig.CodeCoverage.OutputEncoding = 'UTF8' if ($MinimumCoverage -gt 0) { $pesterConfig.CodeCoverage.CoveragePercentTarget = $MinimumCoverage } } Write-Host "Starting test execution..." -ForegroundColor Yellow Write-Host "" # Run tests $result = Invoke-Pester -Configuration $pesterConfig Write-Host "" Write-Host "========================================" -ForegroundColor Cyan Write-Host " Test Results Summary" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan # Display results Write-Host "" Write-Host "Total Tests: " -NoNewline Write-Host $result.TotalCount -ForegroundColor White Write-Host "Passed: " -NoNewline Write-Host $result.PassedCount -ForegroundColor Green Write-Host "Failed: " -NoNewline if ($result.FailedCount -gt 0) { Write-Host $result.FailedCount -ForegroundColor Red } else { Write-Host $result.FailedCount -ForegroundColor Green } Write-Host "Skipped: " -NoNewline Write-Host $result.SkippedCount -ForegroundColor Yellow Write-Host "Not Run: " -NoNewline Write-Host $result.NotRunCount -ForegroundColor Gray Write-Host "" Write-Host "Duration: " -NoNewline Write-Host "$($result.Duration.TotalSeconds) seconds" -ForegroundColor White # Code coverage summary if ($CodeCoverage -and $result.CodeCoverage) { Write-Host "" Write-Host "Code Coverage:" -ForegroundColor Cyan $coverage = $result.CodeCoverage $coveragePercent = 0 if ($coverage.CommandsAnalyzedCount -gt 0) { $coveragePercent = [math]::Round(($coverage.CommandsExecutedCount / $coverage.CommandsAnalyzedCount) * 100, 2) } Write-Host " Commands Analyzed: " -NoNewline Write-Host $coverage.CommandsAnalyzedCount -ForegroundColor White Write-Host " Commands Executed: " -NoNewline Write-Host $coverage.CommandsExecutedCount -ForegroundColor White Write-Host " Commands Missed: " -NoNewline Write-Host $coverage.CommandsMissedCount -ForegroundColor $(if ($coverage.CommandsMissedCount -gt 0) { 'Yellow' } else { 'Green' }) Write-Host " Coverage Percentage: " -NoNewline $coverageColor = if ($coveragePercent -ge 80) { 'Green' } elseif ($coveragePercent -ge 60) { 'Yellow' } else { 'Red' } Write-Host "$coveragePercent%" -ForegroundColor $coverageColor if ($MinimumCoverage -gt 0) { Write-Host " Minimum Required: " -NoNewline Write-Host "$MinimumCoverage%" -ForegroundColor White if ($coveragePercent -lt $MinimumCoverage) { Write-Host "" Write-Host " WARNING: Code coverage $coveragePercent% is below minimum $MinimumCoverage%" -ForegroundColor Red } } } # Output file locations Write-Host "" Write-Host "Output Files:" -ForegroundColor Cyan Write-Host " Test Results: " -NoNewline if (Test-Path $OutputFile) { Write-Host $OutputFile -ForegroundColor Green } else { Write-Host "Not generated" -ForegroundColor Yellow } if ($CodeCoverage) { Write-Host " Code Coverage: " -NoNewline if (Test-Path $CodeCoverageOutputFile) { Write-Host $CodeCoverageOutputFile -ForegroundColor Green } else { Write-Host "Not generated" -ForegroundColor Yellow } } Write-Host "" Write-Host "========================================" -ForegroundColor Cyan # Exit with appropriate code for CI/CD if ($result.FailedCount -gt 0) { Write-Host "" Write-Host "TESTS FAILED" -ForegroundColor Red -BackgroundColor Black Write-Host "" # Show failed tests if ($result.Failed.Count -gt 0) { Write-Host "Failed Tests:" -ForegroundColor Red foreach ($test in $result.Failed) { Write-Host " [$($test.ExpandedPath -replace '\.', ' > ')] " -ForegroundColor Gray -NoNewline Write-Host $test.ErrorRecord.Exception.Message -ForegroundColor Red } Write-Host "" } if ($PassThru) { return $result } exit 1 } # Check code coverage minimum if specified if ($CodeCoverage -and $MinimumCoverage -gt 0 -and $coveragePercent -lt $MinimumCoverage) { Write-Host "" Write-Host "CODE COVERAGE BELOW MINIMUM" -ForegroundColor Red -BackgroundColor Black Write-Host "Coverage: $coveragePercent% | Required: $MinimumCoverage%" -ForegroundColor Red Write-Host "" if ($PassThru) { return $result } exit 1 } Write-Host "" Write-Host "ALL TESTS PASSED" -ForegroundColor Green -BackgroundColor Black Write-Host "" if ($PassThru) { return $result } exit 0 |