/
githubmirror
/
PowerShell
Обзор
Документация
Войти
/
githubmirror
/
PowerShell
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
test/powershell/Host/TabCompletion/BugFix.Tests.ps1
298 строк
13 KB
Dongbo Wang
Handle empty-string and null-value results returned from custom argument completer more properly (#27398)
11 май 2026, 21:59
Не верифицирован
11 май 2026, 21:59
c9ac205
Код
Авторство
О чём код?
# Copyright (c) Microsoft Corporation. # Licensed under the MIT License. Describe "Tab completion bug fix" -Tags "CI" { It "Issue#682 - '[system.manage<tab>' should work" { $result = TabExpansion2 -inputScript "[system.manage" -cursorColumn "[system.manage".Length $result.CompletionMatches | Should -HaveCount 1 $result.CompletionMatches[0].CompletionText | Should -BeExactly "System.Management" } It "Issue#1350 - '1 -sp<tab>' should work" { $result = TabExpansion2 -inputScript "1 -sp" -cursorColumn "1 -sp".Length $result.CompletionMatches | Should -HaveCount 1 $result.CompletionMatches[0].CompletionText | Should -BeExactly "-split" } It "Issue#1350 - '1 -a<tab>' should work" { $result = TabExpansion2 -inputScript "1 -a" -cursorColumn "1 -a".Length $result.CompletionMatches | Should -HaveCount 2 $result.CompletionMatches[0].CompletionText | Should -BeExactly "-and" $result.CompletionMatches[1].CompletionText | Should -BeExactly "-as" } It "Issue#2295 - '[pscu<tab>' should expand to [pscustomobject]" { $result = TabExpansion2 -inputScript "[pscu" -cursorColumn "[pscu".Length $result.CompletionMatches | Should -HaveCount 1 $result.CompletionMatches[0].CompletionText | Should -BeExactly "pscustomobject" } It "Issue#1345 - 'Import-Module -n<tab>' should work" { $cmd = "Import-Module -n" $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length $result.CompletionMatches | Should -HaveCount 2 $result.CompletionMatches[0].CompletionText | Should -BeExactly "-Name" $result.CompletionMatches[1].CompletionText | Should -BeExactly "-NoClobber" } It "Issue#11227 - [CompletionCompleters]::CompleteVariable and [CompletionCompleters]::CompleteType should work" { $result = [System.Management.Automation.CompletionCompleters]::CompleteType("CompletionComple") $result.Count | Should -BeExactly 1 $result[0].CompletionText | Should -BeExactly 'System.Management.Automation.CompletionCompleters' $result = [System.Management.Automation.CompletionCompleters]::CompleteVariable("errorAction") $result.Count | Should -BeExactly 1 $result[0].CompletionText | Should -BeExactly '$ErrorActionPreference' } It "Issue#24756 - Wildcard completions should not return early due to missing results in one container" -Skip:(!$IsWindows) { try { $keys = New-Item -Path @( 'HKCU:\AB1' 'HKCU:\AB2' 'HKCU:\AB2\Test' ) $res = TabExpansion2 -inputScript 'Get-ChildItem -Path HKCU:\AB?\' $res.CompletionMatches.Count | Should -Be 1 $res.CompletionMatches[0].CompletionText | Should -BeExactly "HKCU:\AB2\Test" } finally { if ($keys) { Remove-Item -Path HKCU:\AB? -Recurse -ErrorAction SilentlyContinue } } } Context "Issue#3416 - 'Select-Object'" { BeforeAll { $DatetimeProperties = @((Get-Date).psobject.baseobject.psobject.properties) | Sort-Object -Property Name } It "Issue#3416 - 'Select-Object -ExcludeProperty <tab>' should work" { $cmd = "Get-Date | Select-Object -ExcludeProperty " $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length $result.CompletionMatches | Should -HaveCount $DatetimeProperties.Count $result.CompletionMatches[0].CompletionText | Should -BeExactly $DatetimeProperties[0].Name # Date $result.CompletionMatches[1].CompletionText | Should -BeExactly $DatetimeProperties[1].Name # DateTime } It "Issue#3416 - 'Select-Object -ExpandProperty <tab>' should work" { $cmd = "Get-Date | Select-Object -ExpandProperty " $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length $result.CompletionMatches | Should -HaveCount $DatetimeProperties.Count $result.CompletionMatches[0].CompletionText | Should -BeExactly $DatetimeProperties[0].Name # Date $result.CompletionMatches[1].CompletionText | Should -BeExactly $DatetimeProperties[1].Name # DateTime } } It "Issue#3628 - 'Sort-Object @{<tab>' should work" { $cmd = "Get-Date | Sort-Object @{" $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length $result.CompletionMatches | Should -HaveCount 3 $result.CompletionMatches[0].CompletionText | Should -BeExactly 'Expression' $result.CompletionMatches[1].CompletionText | Should -BeExactly 'Ascending' $result.CompletionMatches[2].CompletionText | Should -BeExactly 'Descending' } It "'Get-Date | Sort-Object @{Expression=<tab>' should work without completion" { $cmd = "Get-Date | Sort-Object @{Expression=" $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length $result.CompletionMatches | Should -HaveCount 0 } It "Issue#5322 - 'Get-Date | Sort-Object @{Expression=...;' should work" { $cmd = "Get-Date | Sort-Object @{Expression=...;" $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length $result.CurrentMatchIndex | Should -Be -1 $result.ReplacementIndex | Should -Be 40 $result.ReplacementLength | Should -Be 0 $result.CompletionMatches[0].CompletionText | Should -BeExactly 'Ascending' $result.CompletionMatches[1].CompletionText | Should -BeExactly 'Descending' } It "Issue#19912 - Tab completion should not crash" { $ISS = [initialsessionstate]::CreateDefault() $Runspace = [runspacefactory]::CreateRunspace($ISS) $Runspace.Open() $OldRunspace = [runspace]::DefaultRunspace try { [runspace]::DefaultRunspace = $Runspace {[System.Management.Automation.CommandCompletion]::CompleteInput('Get-', 3, $null)} | Should -Not -Throw } finally { [runspace]::DefaultRunspace = $OldRunspace $Runspace.Dispose() } } It "Issue#26277 - [CompletionCompleters]::CompleteFilename('') should work" { $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 try { Push-Location -Path $testDir $result = [System.Management.Automation.CompletionCompleters]::CompleteFilename("") $result | Should -Not -Be $null $result | Measure-Object | ForEach-Object -MemberName Count | Should -Be 2 $item1, $item2 = @($result) $item1.ListItemText | Should -BeExactly 'abc.ps1' $item2.ListItemText | Should -BeExactly 'def.py' } finally { 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 } } } }