feat(tui): 配置标量的读改核心(第二轮第一块)

先侦察事实:BackupConfig.psd1 共 99 行 —— 52 行注释、18 行单行标量、3 处嵌套哈希、1 处数组、1 处行内空哈希(SidMap = @{})。所以"外科式改一个值"的边界很明确:**只认单行标量**。值跨行或本身是集合时,"改一行"这个动作没有明确含义 —— 那种就不该在界面上提供(如实显示为只读)。

路径用点号拼(Snapshot.Enabled):同名键在不同嵌套里会出现(Enabled 有两处),只用键名会把它们混成一个。非标量(行内哈希、数组)显式排除。读出来的是**含引号的原文** —— 原样写回才逐字节等价。

判据 12 条,核心是往返:**把每个标量设成它当前的值,文本必须逐字节相同**(含键名对齐与全部注释);真改一个时只有那一行不同、注释行数不变、改完还能读出新值;找不到路径或不是标量必须抛错而不是静默不动。

真实配置上的实测:认出 18 个标量(含 3 组嵌套的点号路径,排除了 SidMap 与 DefaultExcludes),**往返后逐字节相同 = True**。

过程里插入的测试代码带过一行手滑的垃圾(被 Parse 层当场抓住 —— 它是这个仓库最便宜的一道闸),以及一条期望值写错(忘了 Value 含引号)。

验收:test.ps1 9/9 全绿(5.1 与 7);真实清单只读冒烟 4/4。
This commit is contained in:
Shuery committed 2026-09-27 21:00:07 +08:00
1 parent c2bae35506
commit 7733b1bf6d
5 files changed
+150

No files matched your search

+38
View File
@@ -1736,6 +1736,44 @@ Test-Case '主入口:-Quiet 不画界面、菜单能渲染、进不去界面
}
}
Test-Case '配置标量:只认单行标量;改一个值只动那一行;设成当前值则逐字节不变' {
$configPath = Join-Path (Split-Path -Parent $PSScriptRoot) 'BackupConfig.psd1'
$text = Get-Content -LiteralPath $configPath -Raw -Encoding UTF8
$rows = @(Get-BakNRetConfigSetting -Text $text)
Assert-True ($rows.Count -ge 15) ('真实配置里应当认出足够多的标量,实际 ' + $rows.Count)
Assert-Equal "'Backups'" ($rows | Where-Object { $_.Path -eq 'BackupDir' }).Value '顶层标量(读出来的是含引号的原文 —— 原样写回才逐字节等价)'
Assert-Equal 'Snapshot.Enabled' (($rows | Where-Object { $_.Path -eq 'Snapshot.Enabled' }).Path) '嵌套里的键要用点号路径(Enabled 有两处)'
Assert-Equal '$true' (($rows | Where-Object { $_.Path -eq 'Encryption.EncryptHeaders' }).Value) '布尔值按原文读出($true 本身就是原文)'
# 非标量必须被排除:行内空哈希与数组都不是"一行一个值"
Assert-Equal 0 @($rows | Where-Object { $_.Path -eq 'Security.SidMap' }).Count '行内哈希不算标量'
Assert-Equal 0 @($rows | Where-Object { $_.Path -like 'DefaultExcludes*' }).Count '数组不算标量'
# 往返:把每个标量设成它当前的值,文本必须**逐字节相同**(外科式改写的最强形式)
$roundTripped = $text
foreach ($row in $rows) { $roundTripped = Set-BakNRetConfigSetting -Text $roundTripped -Path $row.Path -Value $row.Value }
Assert-Equal $text $roundTripped '每个标量设成当前值后文本逐字节相同'
# 真改一个:只有那一行不同,注释行数不变,并且改完还能读出新值
$changed = Set-BakNRetConfigSetting -Text $text -Path 'BackupDir' -Value "'Backups2'"
$before = @($text -split "`n")
$after = @($changed -split "`n")
Assert-Equal $before.Count $after.Count '行数不变'
Assert-Equal 2 @(Compare-Object -ReferenceObject $before -DifferenceObject $after).Count '只应当有一行不同'
$commentCount = @($before | Where-Object { $_.TrimStart().StartsWith('#') }).Count
Assert-Equal $commentCount @($after | Where-Object { $_.TrimStart().StartsWith('#') }).Count '注释行数不变'
Assert-Equal "'Backups2'" ((Get-BakNRetConfigSetting -Text $changed | Where-Object { $_.Path -eq 'BackupDir' }).Value) '改完还能读出同一个值'
# 找不到 / 不是标量:必须抛错,不能静默不动
$threw = $false
try { Set-BakNRetConfigSetting -Text $text -Path 'No.Such.Key' -Value '1' | Out-Null } catch { $threw = $true }
Assert-True $threw '找不到的路径必须抛错'
$threw2 = $false
try { Set-BakNRetConfigSetting -Text $text -Path 'Security.SidMap' -Value '@{}' | Out-Null } catch { $threw2 = $true }
Assert-True $threw2 '非标量(行内哈希)也必须抛错'
}
# ============================================================================
Remove-Item -LiteralPath $sandbox -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $itemSandbox -Recurse -Force -ErrorAction SilentlyContinue