tests/Categories.Tests.ps1
|
$moduleRoot = Split-Path -Parent $PSScriptRoot Import-Module (Join-Path $moduleRoot 'Octa.psd1') -Force # Category and helper functions are internal (not in FunctionsToExport), so dot-source them # directly for white-box testing - mirrors what Octa.psm1 does on import. . (Join-Path $moduleRoot 'private\ActionHelpers.ps1') . (Join-Path $moduleRoot 'private\ElevationCheck.ps1') Get-ChildItem -Path (Join-Path $moduleRoot 'categories') -Filter '*.ps1' | ForEach-Object { . $_.FullName } Describe 'New-OctaAction' { It 'throws when Reversible is $false without an IrreversibleReason' { { New-OctaAction -TargetType Service -TargetIdentifier 'Foo' -Reversible $false } | Should Throw } It 'accepts Reversible $false with a reason' { $a = New-OctaAction -TargetType Service -TargetIdentifier 'Foo' -Reversible $false -IrreversibleReason 'test' $a.IrreversibleReason | Should Be 'test' } } $categoryFunctions = @( 'Get-OctaTelemetryCategory', 'Get-OctaAppxCategory', 'Get-OctaOneDriveCategory', 'Get-OctaCopilotCategory', 'Get-OctaWidgetsCategory', 'Get-OctaRecallCategory', 'Get-OctaExplorerStartCategory', 'Get-OctaOemSuitesCategory', 'Get-OctaPerformanceCategory', 'Get-OctaPowerCategory', 'Get-OctaUserExperienceCategory', 'Get-OctaGpuCategory', 'Get-OctaServicesCategory', 'Get-OctaDesktopCategory', 'Get-OctaPreferencesCategory', 'Get-OctaGamingCategory', 'Get-OctaAiFeaturesCategory', 'Get-OctaWindowsFeaturesCategory', 'Get-OctaBackgroundActivityCategory', 'Get-OctaRegistryOrphansCategory' ) $isElevated = Test-OctaElevation foreach ($fn in $categoryFunctions) { Describe "$fn" { $category = & $fn # Some categories' scans genuinely require elevation to read all-user state (e.g. # Get-AppxPackage -AllUsers) - only exercise the scan itself when this test session # can actually satisfy that, same as Invoke-OctaCategory would gate it in real use. $canScan = $isElevated -or -not $category.RequiresElevation It 'has a non-empty Id and DisplayName' { $category.Id | Should Not BeNullOrEmpty $category.DisplayName | Should Not BeNullOrEmpty } It 'GetActionsFunction is a dry-run: it only reads state and never throws' { if (-not $canScan) { return } { & $category.GetActionsFunction } | Should Not Throw } It 'GetActionsFunction completes quickly (catches accidental registry wildcard hangs, e.g. HKCR:\*\...)' { if (-not $canScan) { return } $sw = [System.Diagnostics.Stopwatch]::StartNew() & $category.GetActionsFunction | Out-Null $sw.Stop() $sw.Elapsed.TotalSeconds | Should BeLessThan 10 } It 'every returned action has the required fields, and irreversible ones carry a reason' { if (-not $canScan) { return } $actions = & $category.GetActionsFunction foreach ($a in $actions) { $a.TargetType | Should Not BeNullOrEmpty $a.TargetIdentifier | Should Not BeNullOrEmpty if (-not $a.Reversible) { $a.IrreversibleReason | Should Not BeNullOrEmpty } } } } } |