tests/git-aliases-extra.Integration.Tests.ps1
|
$ErrorActionPreference = 'Stop' Set-StrictMode -Version Latest $script:HasGcoAlias = [bool](Get-Command gco -ErrorAction SilentlyContinue) BeforeAll { function Script:Invoke-GitCommand { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$RepoPath, [Parameter(Mandatory = $true)] [string[]]$Arguments, [switch]$AllowFail ) $previousPreference = $ErrorActionPreference $ErrorActionPreference = 'Continue' try { $output = & git -C $RepoPath @Arguments 2>&1 } finally { $ErrorActionPreference = $previousPreference } $exitCode = $LASTEXITCODE $text = ($output | Out-String).Trim() if (-not $AllowFail -and $exitCode -ne 0) { throw "git $($Arguments -join ' ') failed in '$RepoPath' (exit=$exitCode): $text" } [pscustomobject]@{ ExitCode = $exitCode Output = $text } } function Script:Find-BlobPrefixCollision { [CmdletBinding()] param( [string]$Prefix = '8695', [int]$MaxAttempts = 2000000 ) $sha1 = [System.Security.Cryptography.SHA1]::Create() try { for ($i = 0; $i -lt $MaxAttempts; $i++) { $content = "collision-$i" $contentBytes = [Text.Encoding]::ASCII.GetBytes($content) $headerBytes = [Text.Encoding]::ASCII.GetBytes("blob $($contentBytes.Length)`0") $payload = New-Object byte[] ($headerBytes.Length + $contentBytes.Length) [Buffer]::BlockCopy($headerBytes, 0, $payload, 0, $headerBytes.Length) [Buffer]::BlockCopy($contentBytes, 0, $payload, $headerBytes.Length, $contentBytes.Length) $hashBytes = $sha1.ComputeHash($payload) $hash = ([BitConverter]::ToString($hashBytes) -replace '-', '').ToLowerInvariant() if ($hash.StartsWith($Prefix)) { return [pscustomobject]@{ Content = $content Hash = $hash } } } } finally { $sha1.Dispose() } throw "Could not find blob hash prefix '$Prefix' within $MaxAttempts attempts." } [string]$script:RepoRoot = Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '..') | Select-Object -ExpandProperty Path -First 1 $script:ModuleManifest = Join-Path $script:RepoRoot 'git-aliases-extra.psd1' if (Get-Module -ListAvailable -Name git-aliases) { Import-Module git-aliases -DisableNameChecking -ErrorAction SilentlyContinue } Import-Module $script:ModuleManifest -Force $script:HasGcoAlias = [bool](Get-Command gco -ErrorAction SilentlyContinue) } AfterAll { Remove-Module git-aliases-extra -Force -ErrorAction SilentlyContinue } Describe 'git-aliases-extra module' { It 'imports successfully' { Get-Module git-aliases-extra | Should -Not -BeNullOrEmpty } It 'exports expected commands' { Get-Command Test-InGitRepo -ErrorAction Stop | Should -Not -BeNullOrEmpty Get-Command UpMerge -ErrorAction Stop | Should -Not -BeNullOrEmpty Get-Command UpRebase -ErrorAction Stop | Should -Not -BeNullOrEmpty Get-Command Get-Git-Aliases -ErrorAction Stop | Should -Not -BeNullOrEmpty Get-Command gfp -ErrorAction Stop | Should -Not -BeNullOrEmpty Get-Command gsw -ErrorAction Stop | Should -Not -BeNullOrEmpty Get-Command gwt -ErrorAction Stop | Should -Not -BeNullOrEmpty Get-Command gwtr -ErrorAction Stop | Should -Not -BeNullOrEmpty } It 'Test-InGitRepo returns a boolean value outside or inside a repository' { (Test-InGitRepo).GetType().Name | Should -Be 'Boolean' } It 'Get-Git-Aliases resolves custom alias grsh' { $definition = Get-Git-Aliases grsh $definition | Should -Match 'git reset --soft HEAD~1' } It 'Get-Git-Aliases lists aliases from git-aliases-extra' { $allAliasesText = (Get-Git-Aliases | Out-String) $allAliasesText | Should -Match '(?im)^\s*grsh\s+' $allAliasesText | Should -Match '(?im)^\s*gfp\s+' } It 'Get-Git-Aliases returns extras first and keeps alphabetical order per group' { $allAliasesText = (Get-Git-Aliases | Out-String) $lines = $allAliasesText -split "`r?`n" $extrasNames = @() $baseNames = @() $firstBaseLine = -1 $lastExtrasLine = -1 for ($i = 0; $i -lt $lines.Count; $i++) { $line = $lines[$i] if ($line -match '^\s*([^\s]+)\s+extras\s+') { $extrasNames += $matches[1] $lastExtrasLine = $i continue } if ($line -match '^\s*([^\s]+)\s+base\s+') { $baseNames += $matches[1] if ($firstBaseLine -lt 0) { $firstBaseLine = $i } } } $extrasNames.Count | Should -BeGreaterThan 0 $baseNames.Count | Should -BeGreaterThan 0 (($extrasNames -join "`n") -eq (($extrasNames | Sort-Object) -join "`n")) | Should -BeTrue (($baseNames -join "`n") -eq (($baseNames | Sort-Object) -join "`n")) | Should -BeTrue $lastExtrasLine | Should -BeLessThan $firstBaseLine } It 'Get-Git-Aliases -Base returns only base aliases' { $baseAliasesText = (Get-Git-Aliases -Base | Out-String) $baseAliasesText | Should -Match '(?im)^\s*ga\s+' $baseAliasesText | Should -Not -Match '(?im)^\s*grsh\s+' } It 'Get-Git-Aliases -Extras returns only extras aliases' { $extrasAliasesText = (Get-Git-Aliases -Extras | Out-String) $extrasAliasesText | Should -Match '(?im)^\s*grsh\s+' $extrasAliasesText | Should -Not -Match '(?im)^\s*gaa\s+' } It 'Get-Git-Aliases respects source filter for single alias lookup' { $extrasDefinition = Get-Git-Aliases -Alias grsh -Extras $extrasDefinition | Should -Match 'git reset --soft HEAD~1' { Get-Git-Aliases -Alias grsh -Base } | Should -Throw } } Describe 'gfp integration' { It 'creates series.mbox using default base branch resolution' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) { $tempRoot = Join-Path ([IO.Path]::GetTempPath()) ("gfp-default-" + [guid]::NewGuid().Guid) $remotePath = Join-Path $tempRoot 'remote.git' $workPath = Join-Path $tempRoot 'work' New-Item -ItemType Directory -Path $workPath -Force | Out-Null try { Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', '--bare', $remotePath) | Out-Null Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', $workPath) | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('config', 'user.email', 'test@example.com') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('config', 'user.name', 'Test User') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('config', 'commit.gpgsign', 'false') | Out-Null Set-Content -Path (Join-Path $workPath 'README.md') -Value 'root' -NoNewline -Encoding ascii Invoke-GitCommand -RepoPath $workPath -Arguments @('add', 'README.md') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('commit', '-m', 'init main') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('branch', '-M', 'main') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('remote', 'add', 'origin', $remotePath) | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('push', '-u', 'origin', 'main') | Out-Null Add-Content -Path (Join-Path $workPath 'README.md') -Value "`nfeature-from-main" Invoke-GitCommand -RepoPath $workPath -Arguments @('add', 'README.md') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('commit', '-m', 'feature main patch') | Out-Null Push-Location $workPath try { $mboxPath = gfp } finally { Pop-Location } $expectedPath = Join-Path $workPath 'series.mbox' $mboxPath | Should -Be $expectedPath (Test-Path -LiteralPath $expectedPath) | Should -BeTrue $mboxContent = Get-Content -LiteralPath $expectedPath -Raw $mboxContent | Should -Match 'Subject: \[PATCH' $mboxContent | Should -Match 'feature main patch' } finally { if (Test-Path $tempRoot) { Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue } } } It 'supports explicit target branch and custom output mbox path' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) { $tempRoot = Join-Path ([IO.Path]::GetTempPath()) ("gfp-custom-" + [guid]::NewGuid().Guid) $remotePath = Join-Path $tempRoot 'remote.git' $workPath = Join-Path $tempRoot 'work' New-Item -ItemType Directory -Path $workPath -Force | Out-Null try { Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', '--bare', $remotePath) | Out-Null Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', $workPath) | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('config', 'user.email', 'test@example.com') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('config', 'user.name', 'Test User') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('config', 'commit.gpgsign', 'false') | Out-Null Set-Content -Path (Join-Path $workPath 'README.md') -Value 'root' -NoNewline -Encoding ascii Invoke-GitCommand -RepoPath $workPath -Arguments @('add', 'README.md') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('commit', '-m', 'init master') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('branch', '-M', 'master') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('remote', 'add', 'origin', $remotePath) | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('push', '-u', 'origin', 'master') | Out-Null Add-Content -Path (Join-Path $workPath 'README.md') -Value "`nfeature-custom" Invoke-GitCommand -RepoPath $workPath -Arguments @('add', 'README.md') | Out-Null Invoke-GitCommand -RepoPath $workPath -Arguments @('commit', '-m', 'custom output patch') | Out-Null Push-Location $workPath try { $mboxPath = gfp master 'artifacts\custom-series.mbox' } finally { Pop-Location } $expectedPath = Join-Path $workPath 'artifacts\custom-series.mbox' $mboxPath | Should -Be $expectedPath (Test-Path -LiteralPath $expectedPath) | Should -BeTrue $mboxContent = Get-Content -LiteralPath $expectedPath -Raw $mboxContent | Should -Match 'Subject: \[PATCH' $mboxContent | Should -Match 'custom output patch' } finally { if (Test-Path $tempRoot) { Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue } } } } Describe 'gsw integration' { It 'completes branch names for gsw when command is followed by a space' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) { $tempRoot = Join-Path ([IO.Path]::GetTempPath()) ("gsw-space-complete-" + [guid]::NewGuid().Guid) $repoPath = Join-Path $tempRoot 'repo' New-Item -ItemType Directory -Path $repoPath -Force | Out-Null try { Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', $repoPath) | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'user.email', 'test@example.com') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'user.name', 'Test User') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'commit.gpgsign', 'false') | Out-Null Set-Content -Path (Join-Path $repoPath 'README.md') -Value 'root' -NoNewline -Encoding ascii Invoke-GitCommand -RepoPath $repoPath -Arguments @('add', 'README.md') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('commit', '-m', 'init') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('branch', '-M', 'main') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('branch', 'feature/tab-complete') | Out-Null Push-Location $repoPath try { $line = 'gsw ' $result = TabExpansion2 -inputScript $line -cursorColumn $line.Length } finally { Pop-Location } $result.CompletionMatches.Count | Should -BeGreaterThan 0 $completionTexts = @($result.CompletionMatches | Select-Object -ExpandProperty CompletionText) $completionTexts | Should -Contain 'main' $completionTexts | Should -Contain 'feature/tab-complete' $completionTexts | Should -Not -Contain 'switch' } finally { if (Test-Path $tempRoot) { Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue } } } It 'completes long options for gsw alias' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) { Push-Location $script:RepoRoot try { $line = 'gsw --' $result = TabExpansion2 -inputScript $line -cursorColumn $line.Length } finally { Pop-Location } $result.CompletionMatches.Count | Should -BeGreaterThan 0 $completionTexts = @($result.CompletionMatches | Select-Object -ExpandProperty CompletionText) $completionTexts | Should -Contain '--track' } It 'completes long options for gco alias from git-aliases module' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue) -or -not $script:HasGcoAlias) { Push-Location $script:RepoRoot try { $line = 'gco --' $result = TabExpansion2 -inputScript $line -cursorColumn $line.Length } finally { Pop-Location } $result.CompletionMatches.Count | Should -BeGreaterThan 0 $completionTexts = @($result.CompletionMatches | Select-Object -ExpandProperty CompletionText) $completionTexts | Should -Contain '--detach' } It 'returns PowerShell-safe completion text for branches starting with # when escaped prefix is used' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) { $tempRoot = Join-Path ([IO.Path]::GetTempPath()) ("gsw-complete-" + [guid]::NewGuid().Guid) $repoPath = Join-Path $tempRoot 'repo' New-Item -ItemType Directory -Path $repoPath -Force | Out-Null try { Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', $repoPath) | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'user.email', 'test@example.com') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'user.name', 'Test User') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'commit.gpgsign', 'false') | Out-Null Set-Content -Path (Join-Path $repoPath 'README.md') -Value 'root' -NoNewline -Encoding ascii Invoke-GitCommand -RepoPath $repoPath -Arguments @('add', 'README.md') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('commit', '-m', 'init') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('branch', '-M', 'main') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('branch', '#8698') | Out-Null Push-Location $repoPath try { $line = 'gsw `#' $result = TabExpansion2 -inputScript $line -cursorColumn $line.Length } finally { Pop-Location } $result.CompletionMatches.Count | Should -BeGreaterThan 0 $completionTexts = @($result.CompletionMatches | Select-Object -ExpandProperty CompletionText) $completionTexts | Should -Contain "'#8698'" } finally { if (Test-Path $tempRoot) { Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue } } } It 'handles remote-only numeric branch when native switch is ambiguous' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) { $tempRoot = Join-Path ([IO.Path]::GetTempPath()) ("gsw-integration-" + [guid]::NewGuid().Guid) $remotePath = Join-Path $tempRoot 'remote.git' $seedPath = Join-Path $tempRoot 'seed' $clonePath = Join-Path $tempRoot 'clone' New-Item -ItemType Directory -Path $seedPath -Force | Out-Null try { Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', '--bare', $remotePath) | Out-Null Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', $seedPath) | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('config', 'user.email', 'test@example.com') | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('config', 'user.name', 'Test User') | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('config', 'commit.gpgsign', 'false') | Out-Null Set-Content -Path (Join-Path $seedPath 'README.md') -Value 'root' -NoNewline -Encoding ascii Invoke-GitCommand -RepoPath $seedPath -Arguments @('add', 'README.md') | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('commit', '-m', 'init') | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('branch', '-M', 'main') | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('remote', 'add', 'origin', $remotePath) | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('push', '-u', 'origin', 'main') | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('switch', '-c', '8695') | Out-Null Set-Content -Path (Join-Path $seedPath 'feature.txt') -Value 'feature' -NoNewline -Encoding ascii Invoke-GitCommand -RepoPath $seedPath -Arguments @('add', 'feature.txt') | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('commit', '-m', 'feature') | Out-Null Invoke-GitCommand -RepoPath $seedPath -Arguments @('push', '-u', 'origin', '8695') | Out-Null Invoke-GitCommand -RepoPath $tempRoot -Arguments @('clone', $remotePath, $clonePath) | Out-Null Invoke-GitCommand -RepoPath $clonePath -Arguments @('config', 'commit.gpgsign', 'false') | Out-Null $collision = Find-BlobPrefixCollision -Prefix '8695' $collisionFile = Join-Path $clonePath 'collision.txt' Set-Content -Path $collisionFile -Value $collision.Content -NoNewline -Encoding ascii $written = (Invoke-GitCommand -RepoPath $clonePath -Arguments @('hash-object', '-w', $collisionFile)).Output $written | Should -Be $collision.Hash (Invoke-GitCommand -RepoPath $clonePath -Arguments @('cat-file', '-t', '8695')).Output | Should -Be 'blob' Push-Location $clonePath try { $previousPreference = $ErrorActionPreference $ErrorActionPreference = 'Continue' try { $nativeSwitchOutput = & git switch 8695 2>&1 | Out-String $nativeSwitchExitCode = $LASTEXITCODE } finally { $ErrorActionPreference = $previousPreference } $nativeSwitchExitCode | Should -Not -Be 0 $nativeSwitchOutput.Trim() | Should -Match 'unable to read tree|non-commit|invalid reference' $previousPreference = $ErrorActionPreference $ErrorActionPreference = 'Continue' try { gsw 8695 | Out-Null $gswExitCode = $LASTEXITCODE } finally { $ErrorActionPreference = $previousPreference } $gswExitCode | Should -Be 0 } finally { Pop-Location } (Invoke-GitCommand -RepoPath $clonePath -Arguments @('rev-parse', '--abbrev-ref', 'HEAD')).Output | Should -Be '8695' (Invoke-GitCommand -RepoPath $clonePath -Arguments @('rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}')).Output | Should -Be 'origin/8695' } finally { if (Test-Path $tempRoot) { Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue } } } } Describe 'worktree aliases integration' { It 'provides worktree shortcuts and lists worktrees via gwtl' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) { $tempRoot = Join-Path ([IO.Path]::GetTempPath()) ("gwt-shortcuts-" + [guid]::NewGuid().Guid) $repoPath = Join-Path $tempRoot 'repo' $worktreePath = Join-Path $tempRoot 'repo-feature' New-Item -ItemType Directory -Path $repoPath -Force | Out-Null try { Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', $repoPath) | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'user.email', 'test@example.com') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'user.name', 'Test User') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'commit.gpgsign', 'false') | Out-Null Set-Content -Path (Join-Path $repoPath 'README.md') -Value 'root' -NoNewline -Encoding ascii Invoke-GitCommand -RepoPath $repoPath -Arguments @('add', 'README.md') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('commit', '-m', 'init') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('branch', '-M', 'main') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('worktree', 'add', '-b', 'feature/worktree', $worktreePath) | Out-Null Push-Location $repoPath try { $output = gwtl --porcelain | Out-String } finally { Pop-Location } $output | Should -Match 'worktree' $output | Should -Match ([regex]::Escape((Split-Path -Path $worktreePath -Leaf))) } finally { if (Test-Path $tempRoot) { Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue } } } It 'completes worktree paths for gwtr and gwt remove' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) { $tempRoot = Join-Path ([IO.Path]::GetTempPath()) ("gwt-complete-" + [guid]::NewGuid().Guid) $repoPath = Join-Path $tempRoot 'repo' $worktreePath = Join-Path $tempRoot 'repo-feature' New-Item -ItemType Directory -Path $repoPath -Force | Out-Null try { Invoke-GitCommand -RepoPath $tempRoot -Arguments @('init', $repoPath) | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'user.email', 'test@example.com') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'user.name', 'Test User') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('config', 'commit.gpgsign', 'false') | Out-Null Set-Content -Path (Join-Path $repoPath 'README.md') -Value 'root' -NoNewline -Encoding ascii Invoke-GitCommand -RepoPath $repoPath -Arguments @('add', 'README.md') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('commit', '-m', 'init') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('branch', '-M', 'main') | Out-Null Invoke-GitCommand -RepoPath $repoPath -Arguments @('worktree', 'add', '-b', 'feature/worktree', $worktreePath) | Out-Null $expectedLeaf = Split-Path -Path $worktreePath -Leaf Push-Location $repoPath try { $gwtrLine = 'gwtr ' $gwtrResult = TabExpansion2 -inputScript $gwtrLine -cursorColumn $gwtrLine.Length $gwtLine = 'gwt remove ' $gwtResult = TabExpansion2 -inputScript $gwtLine -cursorColumn $gwtLine.Length } finally { Pop-Location } $gwtrResult.CompletionMatches.Count | Should -BeGreaterThan 0 $gwtrTexts = @($gwtrResult.CompletionMatches | Select-Object -ExpandProperty CompletionText) (@($gwtrTexts | Where-Object { $_ -like "*$expectedLeaf*" })).Count | Should -BeGreaterThan 0 $gwtResult.CompletionMatches.Count | Should -BeGreaterThan 0 $gwtTexts = @($gwtResult.CompletionMatches | Select-Object -ExpandProperty CompletionText) (@($gwtTexts | Where-Object { $_ -like "*$expectedLeaf*" })).Count | Should -BeGreaterThan 0 } finally { if (Test-Path $tempRoot) { Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue } } } } |