config editor

This commit is contained in:
2026-08-21 01:18:19 -04:00
parent c30ef6ec24
commit 01d08e635c
15 changed files with 1501 additions and 16 deletions
+133
View File
@@ -0,0 +1,133 @@
#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' }
<#
FR-027: the interactive editor can add a new rule, and rejects a colliding id or
priority before the rule is added.
Add-PersonaConfigRule is exercised directly rather than through the interactive
script - it is the pure function the [A] command calls, and pure functions are
what this suite can test without driving Read-Host through a subprocess (see
NonInteractive.Tests.ps1 for why that path is reserved for hang/prompt proof, not
ordinary behaviour).
#>
BeforeAll {
$repoRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
. (Join-Path $repoRoot 'tests/TestHelpers.ps1')
foreach ($file in (Get-PersonaSourceFile -RepoRoot $repoRoot)) { . $file }
function New-TestRule {
param(
[string] $Id = 'RULE-0500-TEST',
[int] $Priority = 500,
[string] $Persona = 'Employee'
)
[pscustomobject]@{
id = $Id
name = 'Test rule'
description = 'A rule added by a test.'
enabled = $true
priority = $Priority
persona = $Persona
match = [pscustomobject]@{
operator = 'all'
conditions = @([pscustomobject]@{ type = 'property'; property = 'Department'; operator = 'isNotNull' })
}
}
}
}
Describe 'Add-PersonaConfigRule (FR-027)' {
It 'appends the new rule to the collection' {
$existing = @((New-TestRule -Id 'RULE-0010-GUEST' -Priority 10))
$new = New-TestRule -Id 'RULE-0500-TEST' -Priority 500
$result = Add-PersonaConfigRule -Rules $existing -Rule $new
$result.Count | Should -Be 2
($result | Where-Object { [string]$_.id -eq 'RULE-0500-TEST' }).Count | Should -Be 1
}
It 'does not mutate the input collection' {
$existing = @((New-TestRule -Id 'RULE-0010-GUEST' -Priority 10))
$new = New-TestRule -Id 'RULE-0500-TEST' -Priority 500
Add-PersonaConfigRule -Rules $existing -Rule $new | Out-Null
$existing.Count | Should -Be 1
}
It 'always returns an array, even when the result has exactly one rule' {
# The single-element case is the one PowerShell silently collapses to a
# scalar unless the function guards against it (see Add-PersonaConfigRule's
# `, (...)` return) - assigning the call's result directly, with no extra
# @() at this call site, is what proves the function's own guard is doing
# the work rather than an @() here masking a function that does not.
$new = New-TestRule -Id 'RULE-0500-TEST' -Priority 500
$result = Add-PersonaConfigRule -Rules @() -Rule $new
, $result | Should -BeOfType [array]
$result.Count | Should -Be 1
}
It 'rejects a duplicate id before adding' {
$existing = @((New-TestRule -Id 'RULE-0010-GUEST' -Priority 10))
$colliding = New-TestRule -Id 'RULE-0010-GUEST' -Priority 999
{ Add-PersonaConfigRule -Rules $existing -Rule $colliding } | Should -Throw '*RULE-0010-GUEST*'
}
It 'rejects a duplicate priority before adding' {
$existing = @((New-TestRule -Id 'RULE-0010-GUEST' -Priority 10))
$colliding = New-TestRule -Id 'RULE-0500-TEST' -Priority 10
{ Add-PersonaConfigRule -Rules $existing -Rule $colliding } | Should -Throw '*10*'
}
It 'leaves the original collection unchanged when the add is rejected' {
$existing = @((New-TestRule -Id 'RULE-0010-GUEST' -Priority 10))
$colliding = New-TestRule -Id 'RULE-0010-GUEST' -Priority 999
try { Add-PersonaConfigRule -Rules $existing -Rule $colliding } catch { }
$existing.Count | Should -Be 1
}
It 'rejects a blank id' {
$existing = @((New-TestRule -Id 'RULE-0010-GUEST' -Priority 10))
$blank = New-TestRule -Id '' -Priority 999
{ Add-PersonaConfigRule -Rules $existing -Rule $blank } | Should -Throw
}
It 'the added rule survives a full validation pass' {
$document = New-TestConfigurationDocument
$new = @{
id = 'RULE-0500-TEST'
name = 'Test rule'
description = 'A rule added by a test.'
enabled = $true
priority = 500
persona = 'Employee'
match = @{
operator = 'all'
conditions = @(@{ type = 'property'; property = 'Department'; operator = 'isNotNull' })
}
}
$document.rules = Add-PersonaConfigRule -Rules $document.rules -Rule $new
$path = Save-TestConfiguration -Document $document -Directory ([System.IO.Path]::GetTempPath())
try {
$result = Test-PersonaConfiguration -Path $path
$result.IsValid | Should -BeTrue
@($result.Document.rules).Count | Should -Be 3
}
finally {
Remove-Item -LiteralPath $path -Force -ErrorAction SilentlyContinue
}
}
}