tests/RiskLevel.Tests.ps1

$moduleRoot = Split-Path -Parent $PSScriptRoot
Import-Module (Join-Path $moduleRoot 'Octa.psd1') -Force
. (Join-Path $moduleRoot 'private\ActionHelpers.ps1')
Get-ChildItem -Path (Join-Path $moduleRoot 'categories') -Filter '*.ps1' | ForEach-Object { . $_.FullName }

Describe 'New-OctaAction RiskLevel' {
    It 'defaults to Safe when not specified' {
        $a = New-OctaAction -TargetType Registry -TargetIdentifier 'Foo|Bar'
        $a.RiskLevel | Should Be 'Safe'
    }
    It 'accepts Moderate and Risky explicitly' {
        (New-OctaAction -TargetType Registry -TargetIdentifier 'Foo|Bar' -RiskLevel Moderate).RiskLevel | Should Be 'Moderate'
        (New-OctaAction -TargetType Registry -TargetIdentifier 'Foo|Bar' -RiskLevel Risky).RiskLevel | Should Be 'Risky'
    }
}

Describe 'Split-OctaActionsByConfirmationGroup' {
    It 'puts Safe and Moderate actions in the Normal group, never in Risky' {
        $entries = @(
            [pscustomobject]@{ Action = (New-OctaAction -TargetType Registry -TargetIdentifier 'A|A' -RiskLevel Safe) }
            [pscustomobject]@{ Action = (New-OctaAction -TargetType Registry -TargetIdentifier 'B|B' -RiskLevel Moderate) }
        )
        $groups = Split-OctaActionsByConfirmationGroup -Entries $entries
        $groups.Normal.Count | Should Be 2
        $groups.Risky.Count | Should Be 0
        $groups.Heuristic.Count | Should Be 0
    }

    It 'puts Risky actions in their own group, separate from Normal and Heuristic' {
        $entries = @(
            [pscustomobject]@{ Action = (New-OctaAction -TargetType Registry -TargetIdentifier 'A|A' -RiskLevel Safe) }
            [pscustomobject]@{ Action = (New-OctaAction -TargetType Registry -TargetIdentifier 'B|B' -RiskLevel Risky) }
        )
        $groups = Split-OctaActionsByConfirmationGroup -Entries $entries
        $groups.Normal.Count | Should Be 1
        $groups.Risky.Count | Should Be 1
    }

    It 'gives an action that is both HeuristicMatch and Risky only the Risky gate (no double-confirmation)' {
        $entries = @(
            [pscustomobject]@{ Action = (New-OctaAction -TargetType Registry -TargetIdentifier 'A|A' -RiskLevel Risky -HeuristicMatch $true) }
        )
        $groups = Split-OctaActionsByConfirmationGroup -Entries $entries
        $groups.Risky.Count | Should Be 1
        $groups.Heuristic.Count | Should Be 0
    }

    It 'puts a non-Risky irreversible action (e.g. appx package removal) in its own Irreversible group, not Normal' {
        $entries = @(
            [pscustomobject]@{ Action = (New-OctaAction -TargetType Registry -TargetIdentifier 'A|A' -RiskLevel Safe) }
            [pscustomobject]@{ Action = (New-OctaAction -TargetType Package -TargetIdentifier 'B' -Reversible $false -IrreversibleReason 'test') }
        )
        $groups = Split-OctaActionsByConfirmationGroup -Entries $entries
        $groups.Normal.Count | Should Be 1
        $groups.Irreversible.Count | Should Be 1
    }

    It 'gives a Risky-and-irreversible action only the Risky gate (no double-confirmation)' {
        $entries = @(
            [pscustomobject]@{ Action = (New-OctaAction -TargetType Package -TargetIdentifier 'A' -RiskLevel Risky -Reversible $false -IrreversibleReason 'test') }
        )
        $groups = Split-OctaActionsByConfirmationGroup -Entries $entries
        $groups.Risky.Count | Should Be 1
        $groups.Irreversible.Count | Should Be 0
    }
}

Describe 'Get-OctaCategory HighestRiskLevel' {
    It 'reflects the highest RiskLevel among the category''s currently-detected actions' {
        $category = Get-OctaCategory -Id 'user-experience'
        $actions = & $category.GetActionsFunction
        $expectedHighest = 'Safe'
        $rank = @{ Safe = 0; Moderate = 1; Risky = 2 }
        foreach ($a in $actions) {
            if ($rank[$a.RiskLevel] -gt $rank[$expectedHighest]) { $expectedHighest = $a.RiskLevel }
        }
        $category.HighestRiskLevel | Should Be $expectedHighest
    }
}