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