Handle empty-string and null-value results returned from custom argument completer more properly (#27398)

This commit is contained in:
Dongbo Wang
2026-05-11 11:59:37 -07:00
committed by GitHub
parent 7164700777
commit c9ac205fda
4 changed files with 188 additions and 12 deletions
@@ -149,4 +149,150 @@ Describe "Tab completion bug fix" -Tags "CI" {
Pop-Location
}
}
Context 'Native CLI argument completion' {
BeforeAll {
$testDir = Join-Path $TestDrive "TempTestDir"
$file1 = Join-Path $testDir "abc.ps1"
$file2 = Join-Path $testDir "def.py"
New-Item -ItemType Directory -Path $testDir > $null
New-Item -ItemType File -Path $file1 > $null
New-Item -ItemType File -Path $file2 > $null
$dirSep = [System.IO.Path]::DirectorySeparatorChar
$relative_name_abc = ".${dirSep}abc.ps1"
$relative_name_def = ".${dirSep}def.py"
}
AfterAll {
## Unregister the completer for 'ping' to avoid affecting other tests.
register-ArgumentCompleter -Native -CommandName ping -ScriptBlock $null
}
It 'Completer script block returning nothing should fall back to file name completion' {
register-ArgumentCompleter -Native -CommandName ping -ScriptBlock {
param($WordToComplete, $CommandAst, $CursorPosition)
}
try {
Push-Location -Path $testDir
$cmd = "ping "
$result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length
$result.CompletionMatches | Should -Not -BeNullOrEmpty
$result.CompletionMatches.Count | Should -Be 2
$result.CompletionMatches[0].CompletionText | Should -BeExactly $relative_name_abc
$result.CompletionMatches[1].CompletionText | Should -BeExactly $relative_name_def
} finally {
Pop-Location
}
}
It 'Completer script block returning $null should suppress default completion fallback' {
register-ArgumentCompleter -Native -CommandName ping -ScriptBlock {
param($WordToComplete, $CommandAst, $CursorPosition)
return $null
}
try {
Push-Location -Path $testDir
$cmd = "ping "
## This call should not throw, and should suppress the default file name completion fallback, returning no results.
$result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length
$result.CompletionMatches.Count | Should -Be 0
} finally {
Pop-Location
}
}
It 'Completer script block returning empty string should suppress default completion fallback' {
register-ArgumentCompleter -Native -CommandName ping -ScriptBlock {
param($WordToComplete, $CommandAst, $CursorPosition)
return ''
}
try {
Push-Location -Path $testDir
$cmd = "ping "
## This call should not throw, and should suppress the default file name completion fallback, returning no results.
$result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length
$result.CompletionMatches.Count | Should -Be 0
} finally {
Pop-Location
}
}
It 'Completer script block returning empty-string-only array should fall back to default completion' {
register-ArgumentCompleter -Native -CommandName ping -ScriptBlock {
param($WordToComplete, $CommandAst, $CursorPosition)
return '', ''
}
try {
Push-Location -Path $testDir
$cmd = "ping "
## This call should not throw, and should fall back to the default completion.
$result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length
$result.CompletionMatches.Count | Should -Be 2
$result.CompletionMatches[0].CompletionText | Should -BeExactly $relative_name_abc
$result.CompletionMatches[1].CompletionText | Should -BeExactly $relative_name_def
} finally {
Pop-Location
}
}
It 'Completer script block returning null-value-only array should fall back to default completion' {
register-ArgumentCompleter -Native -CommandName ping -ScriptBlock {
param($WordToComplete, $CommandAst, $CursorPosition)
return $null, $null
}
try {
Push-Location -Path $testDir
$cmd = "ping "
## This call should not throw, and should fall back to the default completion.
$result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length
$result.CompletionMatches.Count | Should -Be 2
$result.CompletionMatches[0].CompletionText | Should -BeExactly $relative_name_abc
$result.CompletionMatches[1].CompletionText | Should -BeExactly $relative_name_def
} finally {
Pop-Location
}
}
It 'Completer script block returning a single string works as expected' {
register-ArgumentCompleter -Native -CommandName ping -ScriptBlock {
param($WordToComplete, $CommandAst, $CursorPosition)
return 'hello'
}
try {
Push-Location -Path $testDir
$cmd = "ping "
$result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length
$result.CompletionMatches.Count | Should -Be 1
$result.CompletionMatches[0].CompletionText | Should -BeExactly "hello"
} finally {
Pop-Location
}
}
It 'Completer script block returning an array that contains non-empty-or-null strings works as expected' {
register-ArgumentCompleter -Native -CommandName ping -ScriptBlock {
param($WordToComplete, $CommandAst, $CursorPosition)
return '', 'hello', $null, 'world'
}
try {
Push-Location -Path $testDir
$cmd = "ping "
$result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length
$result.CompletionMatches.Count | Should -Be 2
$result.CompletionMatches[0].CompletionText | Should -BeExactly "hello"
$result.CompletionMatches[1].CompletionText | Should -BeExactly "world"
} finally {
Pop-Location
}
}
}
}