tests/completion_probe.ps1
|
<#
fount 命令补全的自检:用命令行字符串造 AST,直接调 Get-FountArgumentCompletion。 只断言与已装 part 无关的补全结果,依赖 part 内容的位置只打印出来供人肉核对。 用法:pwsh -File tests/completion_probe.ps1 #> param([string]$RepoRoot = (Split-Path -Parent $PSScriptRoot)) if (-not (Get-Command fount.ps1 -ErrorAction Ignore)) { Write-Host '找不到 fount.ps1,先装上 fount 再跑这个自检。' -ForegroundColor Red exit 1 } . "$RepoRoot/data.ps1" . "$RepoRoot/argument_completer.ps1" $script:Failures = 0 # 取 $Line 在 $Cursor 处的补全结果文本($Cursor 为负表示行尾)。 # Get-FountArgumentCompletion 的 catch 会吞掉内部异常只打个 Write-Host,所以这里把信息流也捞出来当失败。 function Get-Completion([string]$Line, [int]$Cursor = -1) { if ($Cursor -lt 0) { $Cursor = $Line.Length } $ast = [System.Management.Automation.Language.Parser]::ParseInput($Line, [ref]$null, [ref]$null) $commandAst = $ast.Find({ param($node) $node -is [System.Management.Automation.Language.CommandAst] }, $true) $wordToComplete = ($Line.Substring(0, $Cursor) -split '\s+')[-1] $merged = @(Get-FountArgumentCompletion -WordToComplete $wordToComplete -CommandAst $commandAst -CursorPosition $Cursor 6>&1) $errors = @($merged | Where-Object { $_ -is [System.Management.Automation.InformationRecord] }) if ($errors) { throw "补全内部报错: $(($errors | ForEach-Object { $_.MessageData.Message }) -join ' / ')" } $merged | ForEach-Object { if ($_ -is [System.Management.Automation.CompletionResult]) { $_.CompletionText } else { $_ } } } function Get-CompletionText([string]$Line, [int]$Cursor = -1) { @(Get-Completion $Line $Cursor) -join ' ' } function Assert-Completion([string]$Line, [string[]]$Expected, [int]$Cursor = -1) { if ($Cursor -lt 0) { $Cursor = $Line.Length } try { $actualText = Get-CompletionText $Line $Cursor } catch { $script:Failures++; Write-Host "FAIL <$Line>@$Cursor`n $($_.Exception.Message)" -ForegroundColor Red; return } $expectedText = $Expected -join ' ' if ($actualText -eq $expectedText) { Write-Host "ok <$Line>@$Cursor -> $actualText" -ForegroundColor Green } else { $script:Failures++ Write-Host "FAIL <$Line>@$Cursor`n 期望 $expectedText`n 实际 $actualText" -ForegroundColor Red } } function Show-Completion([string]$Line, [int]$Cursor = -1) { if ($Cursor -lt 0) { $Cursor = $Line.Length } try { $text = Get-CompletionText $Line $Cursor } catch { $text = "报错:$($_.Exception.Message)" } Write-Host " <$Line>@$Cursor -> $text" } $rootCommands = 'background', 'clean', 'debug', 'eval', 'geneexe', 'init', 'keepalive', 'log', 'logo', 'nop', 'open', 'reboot', 'remove', 'run', 'runas', 'server', 'shutdown', 'test', 'update', 'version' # 非 Windows 上 argument_completer.ps1 会摘掉 geneexe。 if (-not $IsWindows) { $rootCommands = $rootCommands -ne 'geneexe' } # 各命令节点接受的参数。 Assert-Completion 'fount ' $rootCommands Assert-Completion 'fount ru' 'run', 'runas' Assert-Completion 'fount background ' ($rootCommands -ne 'background') Assert-Completion 'fount background keepalive ' 'debug', 'run', 'runas' Assert-Completion 'fount keepalive debug ' 'run', 'runas' # 没有子参数的叶子命令不该补出东西,也不该报错。 Assert-Completion 'fount init ' @() Assert-Completion 'fount background init ' @() # 光标停在参数中间/后面时,后面的参数不该改变当前层级。 Assert-Completion 'fount run ' $rootCommands -Cursor 6 # 拿变量当参数时不该炸。 Assert-Completion 'fount run $part ' @() # 依赖已装 part 与用户名,只打印。 $username = Get-FountUserList | Select-Object -First 1 Show-Completion 'fount run ' Show-Completion 'fount run ch' Show-Completion 'fount runas ' Show-Completion "fount runas $username " Show-Completion "fount runas $username shells/" if ($script:Failures) { Write-Host "$script:Failures 项失败" -ForegroundColor Red exit 1 } Write-Host '全部通过' -ForegroundColor Green exit 0 |