#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } BeforeAll { $repoRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent foreach ($f in @( 'src/Normalization/New-PersonaMembershipRecord.ps1' 'src/Normalization/New-PersonaUserRecord.ps1' 'src/RuleEngine/Test-PersonaCondition.ps1' 'src/RuleEngine/Test-PersonaConditionGroup.ps1' 'src/RuleEngine/Test-PersonaRule.ps1' 'src/RuleEngine/Resolve-UserPersona.ps1' )) { . (Join-Path $repoRoot $f) } $script:user = New-PersonaUserRecord ` -AccountObjectId '00000000-0000-0000-0000-000000000105' ` -UserPrincipalName 'ellis.minimal@example.invalid' ` -UserType 'Member' ` -StoredPersona 'Employee' function New-NonMatchingRule { param([string] $Id, [int] $Priority) [pscustomobject]@{ id = $Id; priority = $Priority; persona = 'Tier0-Admin'; enabled = $true match = [pscustomobject]@{ operator = 'all' conditions = @([pscustomobject]@{ type = 'property'; property = 'Department'; operator = 'equals'; value = 'NoSuchDepartment' }) } } } } Describe 'Unclassified outcome (FR-010)' { It 'is the result when every enabled rule evaluates successfully and none match' { $result = Resolve-UserPersona -UserRecord $user -Rules @( New-NonMatchingRule -Id 'R-010' -Priority 10 New-NonMatchingRule -Id 'R-020' -Priority 20 ) $result.Outcome | Should -Be 'Unclassified' $result.CalculatedPersona | Should -Be 'Unclassified' $result.MatchedRuleId | Should -BeNullOrEmpty } It 'evaluates every enabled rule before concluding' { $result = Resolve-UserPersona -UserRecord $user -Rules @( New-NonMatchingRule -Id 'R-010' -Priority 10 New-NonMatchingRule -Id 'R-020' -Priority 20 New-NonMatchingRule -Id 'R-030' -Priority 30 ) $result.RulesEvaluated | Should -Be 3 } It 'is the result for an empty rule set' { $result = Resolve-UserPersona -UserRecord $user -Rules @() $result.Outcome | Should -Be 'Unclassified' } It 'is the result when every rule is disabled' { $disabled = New-NonMatchingRule -Id 'R-010' -Priority 10 $disabled.enabled = $false $result = Resolve-UserPersona -UserRecord $user -Rules @($disabled) $result.Outcome | Should -Be 'Unclassified' $result.RulesEvaluated | Should -Be 0 } It 'is reported distinctly from EvaluationError' { # Both mean "no persona was assigned", but only one means the engine failed. # Conflating them would hide data-availability problems inside a normal- # looking result bucket. $result = Resolve-UserPersona -UserRecord $user -Rules @(New-NonMatchingRule -Id 'R-010' -Priority 10) $result.Outcome | Should -Not -Be 'EvaluationError' $result.EvaluationErrorReason | Should -BeNullOrEmpty } It 'preserves the stored persona on the result for later comparison' { (Resolve-UserPersona -UserRecord $user -Rules @(New-NonMatchingRule -Id 'R-010' -Priority 10)).StoredPersona | Should -Be 'Employee' } }