diff --git a/.githooks/pre-commit.ps1 b/.githooks/pre-commit.ps1 index 107a78a..682cea0 100644 --- a/.githooks/pre-commit.ps1 +++ b/.githooks/pre-commit.ps1 @@ -3,14 +3,31 @@ $ErrorActionPreference = 'Stop' $testScript = 'PowerShell/system-administration/maintenance/system-maintenance.ps1' $testPath = 'tests/unit/PowerShell/system-maintenance.Tests.ps1' -$resultsPath = 'tests/results/system-maintenance.json' +$resultsPath = 'tests/results/system-maintenance.xml' if (Test-Path $testPath) { Write-Host "Running Pester tests for $testScript..." - Invoke-Pester -Script $testPath -OutputFormat NUnitXml -OutputFile $resultsPath + + # Set SCRIPTS_ROOT environment variable for tests + $env:SCRIPTS_ROOT = (Get-Location).Path + + # Use Pester v5 configuration syntax + $config = New-PesterConfiguration + $config.Run.Path = $testPath + $config.Run.PassThru = $true + $config.TestResult.Enabled = $true + $config.TestResult.OutputPath = $resultsPath + $config.TestResult.OutputFormat = 'JUnitXml' + + $result = Invoke-Pester -Configuration $config + + if ($result.FailedCount -gt 0) { + Write-Host "Tests failed. Aborting commit." + exit 1 + } + if (Test-Path $resultsPath) { - git add $resultsPath - Write-Host "Test results saved and staged: $resultsPath" + Write-Host "Test results saved to: $resultsPath" } else { Write-Host "Test results not found, aborting commit." diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c63a128..db512fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,18 +38,18 @@ jobs: id: check_results shell: pwsh run: | - $resultsPath = 'tests/results/system-maintenance.json' + $resultsPath = 'tests/results/system-maintenance.xml' if (Test-Path $resultsPath) { $fileAge = (Get-Date) - (Get-Item $resultsPath).LastWriteTime if ($fileAge.TotalDays -lt 2) { - Write-Host "::set-output name=found::true" + echo "found=true" >> $env:GITHUB_OUTPUT } else { Write-Host "Test results are too old." - Write-Host "::set-output name=found::false" + echo "found=false" >> $env:GITHUB_OUTPUT } } else { Write-Host "No local test results found." - Write-Host "::set-output name=found::false" + echo "found=false" >> $env:GITHUB_OUTPUT } - name: Use local test results if available diff --git a/.gitignore b/.gitignore index 2c469d8..9a81d3d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ #Ignore vscode AI rules .github\instructions\codacy.instructions.md + +# Test results +tests/results/ diff --git a/tests/unit/PowerShell/system-maintenance.Tests.ps1 b/tests/unit/PowerShell/system-maintenance.Tests.ps1 index e289993..96f056d 100644 --- a/tests/unit/PowerShell/system-maintenance.Tests.ps1 +++ b/tests/unit/PowerShell/system-maintenance.Tests.ps1 @@ -34,30 +34,26 @@ Describe "system-maintenance.ps1" { } $scriptPathCandidate = Join-Path $scriptsRoot "PowerShell/system-administration/maintenance/system-maintenance.ps1" if (-not (Test-Path $scriptPathCandidate)) { - # Try absolute path as fallback - $scriptPathCandidate = "F:\April\Scripts\PowerShell\system-administration\maintenance\system-maintenance.ps1" - if (-not (Test-Path $scriptPathCandidate)) { - throw "Script not found at: $scriptPathCandidate" - } + throw "Script not found at: $scriptPathCandidate. Ensure SCRIPTS_ROOT is set correctly or run from repository root." } $script:scriptPath = Resolve-Path $scriptPathCandidate | Select-Object -ExpandProperty Path } Context "Basic Script Validation" { It "should be a valid script file" { - Test-Path -Path $scriptPath | Should Be $true + Test-Path -Path $scriptPath | Should -Be $true } It "should have comment-based help" { $help = Get-Help $scriptPath -ErrorAction SilentlyContinue $notNull = $false if ($help -and $help.Name -eq 'system-maintenance.ps1') { $notNull = $true } - $notNull | Should Be $true + $notNull | Should -Be $true } It "should support -WhatIf" { # For scripts, -WhatIf is not a formal parameter, but script logic should handle it $content = Get-Content -Path $scriptPath -Raw - ($content -like '*WhatIf*') | Should Be $true + ($content -like '*WhatIf*') | Should -Be $true } } @@ -71,7 +67,7 @@ Describe "system-maintenance.ps1" { $threw = $false } catch { $threw = $true } - $threw | Should Be $true + $threw | Should -Be $true } It "should reject MaxTempFileAgeDays above maximum (> 3650)" { @@ -81,7 +77,7 @@ Describe "system-maintenance.ps1" { $threw = $false } catch { $threw = $true } - $threw | Should Be $true + $threw | Should -Be $true } It "should reject non-numeric MaxTempFileAgeDays" { @@ -91,7 +87,7 @@ Describe "system-maintenance.ps1" { $threw = $false } catch { $threw = $true } - $threw | Should Be $true + $threw | Should -Be $true } } @@ -100,7 +96,7 @@ Describe "system-maintenance.ps1" { Context "Permissions and Prerequisites" { It "should have #Requires -RunAsAdministrator directive" { $content = Get-Content -Path $scriptPath -Raw - $content -match '#Requires\s+-RunAsAdministrator' | Should Be $true + $content -match '#Requires\s+-RunAsAdministrator' | Should -Be $true } # Note: Testing actual permission failures requires running in a non-admin context, @@ -118,7 +114,7 @@ Describe "system-maintenance.ps1" { foreach ($attr in $command.Parameters['MaxTempFileAgeDays'].Attributes) { if ($attr -is [System.Management.Automation.ParameterAttribute]) { $count++ } } - ($count -gt 0) | Should Be $true + ($count -gt 0) | Should -Be $true } } @@ -128,38 +124,38 @@ Describe "system-maintenance.ps1" { $cmdletBinding = $command.ScriptBlock.Attributes | Where-Object { $_ -is [System.Management.Automation.CmdletBindingAttribute] } $hasImpact = $false if ($cmdletBinding -and $cmdletBinding.ConfirmImpact) { $hasImpact = $true } - $hasImpact | Should Be $true + $hasImpact | Should -Be $true } } Context "Logging and Output" { It "should create log file path using Get-LogFilePath function" { $content = Get-Content -Path $scriptPath -Raw - ($content -like '*function Get-LogFilePath*') | Should Be $true + ($content -like '*function Get-LogFilePath*') | Should -Be $true } It "should handle environment where MyDocuments is not available" { $content = Get-Content -Path $scriptPath -Raw - ($content -like '*IsNullOrWhiteSpace*userDocs*') | Should Be $true - ($content -like '*GetTempPath*') | Should Be $true + ($content -like '*IsNullOrWhiteSpace*userDocs*') | Should -Be $true + ($content -like '*GetTempPath*') | Should -Be $true } } Context "Error Handling" { It "should use StrictMode" { $content = Get-Content -Path $scriptPath -Raw - ($content -like '*Set-StrictMode*Latest*') | Should Be $true + ($content -like '*Set-StrictMode*Latest*') | Should -Be $true } It "should set ErrorActionPreference appropriately" { $content = Get-Content -Path $scriptPath -Raw - ($content -like '*$ErrorActionPreference*Stop*') | Should Be $true + ($content -like '*$ErrorActionPreference*Stop*') | Should -Be $true } It "should include try-catch blocks for error handling" { $content = Get-Content -Path $scriptPath -Raw $tryCount = ($content -split 'try\s*\{').Count - ($tryCount -gt 5) | Should Be $true + ($tryCount -gt 5) | Should -Be $true } } }