feat(tui): 名录字段的读改核心(第三轮第一块)
先侦察事实(232 行、71 个 Slot 级字段):**可编辑面比预想的还窄,边界落在一条可判定的规则上** —— Encrypt 19 个全是单行(可编辑),Description 24 个单行 + 1 个跨行(Edge 那条多行说明,只读),Path / Exclude 一律只读(Scoop 三条带 $(if ($env:SCOOP_GLOBAL){...}) 表达式、Edge 的 Exclude 是跨行拼接)。
规则:**只有单行的 Encrypt / Description 可编辑** —— 与 ADR-0013 的"按能不能安全往返来定"一致:"改一行"对动态表达式与跨行拼接没有明确含义。
扫描时跳过块注释:文件头部模板里有 SoftWareName = @{ ... } 示例,纯文本扫描会把它当成一个软件(实测踩到)。定位靠 (软件名, Slot, 字段名) 三元组且要求唯一命中,命中 0 个或多个都抛错。
实测五个事实:认出 70 个字段、可编辑 43 个(19+24)、往返**逐字节相同 = True**、真改一个只动一行、Edge 的跨行 Description 正确地只读。
过程里两处自己的坑都被门禁逮住:插入的测试代码带过一行手滑垃圾(Parse 层当场报),以及函数文档注释里写了块注释的闭合符号 —— 它提前结束了那段注释,后半句变成代码,而它是**合法语法**所以解析层抓不到、跑到才炸(与"左边空的赋值"同族)。
验收:test.ps1 9/9 全绿(5.1 与 7)。
This commit is contained in:
1 parent
4aa44e8965
commit
8c018533c9
5 files changed
+156
No files matched your search
@@ -1818,6 +1818,53 @@ Test-Case '配置编辑器:脚本驱动改一个值,只动那一行且留下
|
||||
}
|
||||
}
|
||||
|
||||
Test-Case '名录字段:只有单行的 Encrypt / Description 可编辑;改一个只动那一行;往返逐字节等价' {
|
||||
$catalogPath = Join-Path (Split-Path -Parent $PSScriptRoot) 'SoftwareCatalog.psd1'
|
||||
$text = Get-Content -LiteralPath $catalogPath -Raw -Encoding UTF8
|
||||
$fields = @(Get-BakNRetCatalogField -Text $text)
|
||||
|
||||
Assert-True ($fields.Count -ge 60) ('应当认出足够多的 Slot 字段,实际 ' + $fields.Count)
|
||||
# 头部注释模板里的 SoftWareName 示例必须被排除(块注释要跳过)
|
||||
Assert-Equal 0 @($fields | Where-Object { $_.App -eq 'SoftWareName' }).Count '模板示例不该被当成软件'
|
||||
|
||||
# 可编辑面的规则:只有单行的 Encrypt / Description
|
||||
$editable = @($fields | Where-Object { $_.Editable })
|
||||
Assert-True ($editable.Count -ge 40) ('可编辑字段应当有四十多个,实际 ' + $editable.Count)
|
||||
Assert-Equal 0 @($editable | Where-Object { $_.Key -notin @('Encrypt', 'Description') }).Count '只有 Encrypt / Description 可编辑'
|
||||
Assert-Equal 0 @($fields | Where-Object { $_.Key -eq 'Path' -and $_.Editable }).Count 'Path 一律只读(常带 $() 表达式)'
|
||||
Assert-Equal 0 @($fields | Where-Object { $_.Key -eq 'Exclude' -and $_.Editable }).Count 'Exclude 一律只读(Edge 那条是跨行拼接)'
|
||||
# Edge 的 Description 是跨行的:必须只读
|
||||
$edgeDescription = @($fields | Where-Object { $_.App -eq 'MicrosoftEdge' -and $_.Key -eq 'Description' })
|
||||
Assert-Equal 1 $edgeDescription.Count 'Edge 的 Description 应当认出来'
|
||||
Assert-Equal $false $edgeDescription[0].Editable '跨行的 Description 必须只读'
|
||||
|
||||
# 往返:把每个可编辑字段设成它当前的值,文本必须逐字节相同
|
||||
$roundTripped = $text
|
||||
foreach ($field in $editable) {
|
||||
$roundTripped = Set-BakNRetCatalogField -Text $roundTripped -App $field.App -Slot $field.Slot -Key $field.Key -Value $field.Value
|
||||
}
|
||||
Assert-Equal $text $roundTripped '每个可编辑字段设成当前值后文本逐字节相同'
|
||||
|
||||
# 真改一个(AutoDarkMode 的 Encrypt),只动那一行、注释行数不变、改完能读回新值
|
||||
$changed = Set-BakNRetCatalogField -Text $text -App 'AutoDarkMode' -Slot 'DefaultData' -Key 'Encrypt' -Value '$false'
|
||||
$before = @($text -split "`n")
|
||||
$after = @($changed -split "`n")
|
||||
Assert-Equal 2 @(Compare-Object -ReferenceObject $before -DifferenceObject $after).Count '只应当有一行不同'
|
||||
Assert-Equal @($before | Where-Object { $_.TrimStart().StartsWith('#') }).Count @($after | Where-Object { $_.TrimStart().StartsWith('#') }).Count '注释行数不变'
|
||||
Assert-Equal '$false' ((Get-BakNRetCatalogField -Text $changed | Where-Object { $_.App -eq 'AutoDarkMode' -and $_.Key -eq 'Encrypt' }).Value) '改完能读回新值'
|
||||
|
||||
# 拒绝:不可编辑的字段、跨行的 Description、不存在的字段,都必须抛错
|
||||
foreach ($bad in @(
|
||||
@{ A = 'AutoDarkMode'; S = 'DefaultData'; K = 'Path' },
|
||||
@{ A = 'MicrosoftEdge'; S = 'DefaultData'; K = 'Description' },
|
||||
@{ A = 'NoSuchApp'; S = 'NoSuchSlot'; K = 'Encrypt' }
|
||||
)) {
|
||||
$threw = $false
|
||||
try { Set-BakNRetCatalogField -Text $text -App $bad.A -Slot $bad.S -Key $bad.K -Value 'x' | Out-Null } catch { $threw = $true }
|
||||
Assert-True $threw ('应当拒绝:' + $bad.A + '.' + $bad.S + '.' + $bad.K)
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
Remove-Item -LiteralPath $sandbox -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -LiteralPath $itemSandbox -Recurse -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Reference in new issue
Block a user