From 6315c72f69c9ea3dbc6dfe521d2f44988c595c94 Mon Sep 17 00:00:00 2001 From: Shuery <2463253700@qq.com> Date: Sun, 27 Sep 2026 16:11:17 +0800 Subject: [PATCH] =?UTF-8?q?fix(tui):=20=E5=8D=95=E9=94=AE=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E8=A2=AB=20[pscustomobject]=20=E6=8B=86=E6=88=90?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=EF=BC=88=E9=A9=B1=E5=8A=A8=E5=99=A8?= =?UTF-8?q?=E6=94=B9=20List[string]=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:`[pscustomobject]@{ Script = $scriptKeys }` 里,**单元素数组会被 PowerShell 拆成字符串**,于是 `$Driver.Script[0]` 取到的是字符串首字母 —— @('Esc') 变成 'E',键名不再匹配任何分支,循环继续往下读,最后"序列用尽"报错。 这个坑只在"恰好一个键"时出现,所以块 ② 当时的断言(两键序列按顺序消费)看不见它;而菜单循环那块因此连着两次"看着对、跑起来不对"。修法是改用 List[string]:不会被拆、可按索引取、两个版本行为一致。 补一条正是为它立的断言:单键序列必须整键返回(不是首字母)。这类"只在边界数量上出现"的错,只能靠把边界数量本身写进断言来防。 验收:test.ps1 9/9 全绿(5.1 与 7)。 --- BakNRet/Public/New-BakNRetInputDriver.ps1 | 15 +++++++++------ tests/Run-Tests.ps1 | 3 +++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/BakNRet/Public/New-BakNRetInputDriver.ps1 b/BakNRet/Public/New-BakNRetInputDriver.ps1 index 281f367..92ab114 100644 --- a/BakNRet/Public/New-BakNRetInputDriver.ps1 +++ b/BakNRet/Public/New-BakNRetInputDriver.ps1 @@ -22,12 +22,15 @@ throw '指定了 -NonInteractive 但没有给出 -Script:没有可用的输入来源。' } - # 先把数组算好,再放进哈希。 - # 两个都踩过的坑:① `if` 是**语句**不是表达式,写在哈希字面量的值位置上会得不到结果; - # ② 不能写 @($Script) —— $Script 为 $null 时 @($null) 会造出**一个含 $null 的单元素数组**, - # 于是"空序列"被当成"有一个键",读者静默返回 $null 而不报错(而且两个 PowerShell 版本表现 - # 还不一样:实测 7 静默返回、5.1 抛错)。所以显式分岔,让"没有序列"就是 0 个元素。 - $scriptKeys = if ($Script) { @($Script) } else { @() } + # 用 List[string] 而不是数组。三个坑都踩过: + # ① `if` 是**语句**不是表达式,写在哈希字面量的值位置上会得不到结果; + # ② @($null) 会造出**一个含 $null 的单元素数组**,于是"空序列"被当成"有一个键"; + # ③ **单元素数组存进 [pscustomobject] 会被拆成字符串** —— 于是 $Driver.Script[0] 取到的是 + # 字符串的首字母(@('Esc') 变成 'E'),键名不再匹配、循环继续读、最后序列用尽。 + # 这个坑只在"恰好一个键"时出现,所以只跑多键序列的断言看不见它(实测栽过一次)。 + # List[string] 不会被拆,也能按索引取,两个版本行为一致。 + $scriptKeys = [System.Collections.Generic.List[string]]::new() + foreach ($entry in @($Script)) { if ($entry) { $scriptKeys.Add([string]$entry) } } return [pscustomobject]@{ Script = $scriptKeys diff --git a/tests/Run-Tests.ps1 b/tests/Run-Tests.ps1 index 0459fc3..50b09f8 100644 --- a/tests/Run-Tests.ps1 +++ b/tests/Run-Tests.ps1 @@ -1447,6 +1447,7 @@ Test-Case '按键归一化与输入缝:映射可无控制台测,序列用尽 # 驱动:按序列顺序消费(这一条曾经因为 Script 被折进注释而静默变成"没有序列") $driver = New-BakNRetInputDriver -Script @('Down', 'Enter') Assert-Equal 2 $driver.Script.Count '驱动里应当有两个键' + # 单键序列:单元素数组会被 [pscustomobject] 拆成字符串,于是 [0] 变成首字母 —— 这条断言就是 # 为那个坑立的(块 ② 当时只覆盖了两键序列,所以它溜过去了)。 $single = New-BakNRetInputDriver -Script @('Esc') Assert-Equal 'Esc' (Read-BakNRetKey -Driver $single) '单键序列必须整键返回(不是首字母)' Assert-Equal 'Down' (Read-BakNRetKey -Driver $driver) '第一个键' Assert-Equal 'Enter' (Read-BakNRetKey -Driver $driver) '第二个键' @@ -1520,6 +1521,8 @@ Test-Case '菜单状态机:绕回、空格切换、确认/取消、空菜单 Assert-Equal 'cancel' (Update-BakNRetMenuState -Items $empty -Key 'Esc').Action '空菜单仍然能退出' } + + # ============================================================================ Remove-Item -LiteralPath $sandbox -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -LiteralPath $itemSandbox -Recurse -Force -ErrorAction SilentlyContinue