diff --git a/src/GitTabExpansion.ps1 b/src/GitTabExpansion.ps1 index f8a6751b0..f4f2829eb 100644 --- a/src/GitTabExpansion.ps1 +++ b/src/GitTabExpansion.ps1 @@ -51,6 +51,16 @@ catch { Write-Debug "Search for 'flow' in 'git help' output failed with error: $_" } +filter quoteStringWithSpecialChars { + if ($_ -and ($_ -match '\s+|#|@|\$|;|,|''|\{|\}|\(|\)')) { + $str = $_ -replace "'", "''" + "'$str'" + } + else { + $_ + } +} + function script:gitCommands($filter, $includeAliases) { $cmdList = @() if (-not $global:GitTabSettings.AllCommands) { @@ -86,7 +96,8 @@ function script:gitBranches($filter, $includeHEAD = $false, $prefix = '') { $branches | Where-Object { $_ -ne '(no branch)' -and $_ -like "$filter*" } | - ForEach-Object { $prefix + $_ } + ForEach-Object { $prefix + $_ } | + quoteStringWithSpecialChars } function script:gitRemoteUniqueBranches($filter) { @@ -95,13 +106,15 @@ function script:gitRemoteUniqueBranches($filter) { Group-Object -NoElement | Where-Object { $_.Count -eq 1 } | Select-Object -ExpandProperty Name | - Where-Object { $_ -like "$filter*" } + Where-Object { $_ -like "$filter*" } | + quoteStringWithSpecialChars } function script:gitTags($filter, $prefix = '') { git tag | Where-Object { $_ -like "$filter*" } | - ForEach-Object { $prefix + $_ } + ForEach-Object { $prefix + $_ } | + quoteStringWithSpecialChars } function script:gitFeatures($filter, $command){ @@ -109,31 +122,33 @@ function script:gitFeatures($filter, $command){ $branches = @(git branch --no-color | ForEach-Object { if ($_ -match "^\*?\s*$featurePrefix(?.*)") { $matches['ref'] } }) $branches | Where-Object { $_ -ne '(no branch)' -and $_ -like "$filter*" } | - ForEach-Object { $prefix + $_ } + ForEach-Object { $prefix + $_ } | + quoteStringWithSpecialChars } function script:gitRemoteBranches($remote, $ref, $filter, $prefix = '') { git branch --no-color -r | Where-Object { $_ -like " $remote/$filter*" } | - ForEach-Object { $prefix + $ref + ($_ -replace " $remote/","") } + ForEach-Object { $prefix + $ref + ($_ -replace " $remote/","") } | + quoteStringWithSpecialChars } function script:gitStashes($filter) { (git stash list) -replace ':.*','' | Where-Object { $_ -like "$filter*" } | - ForEach-Object { "'$_'" } + quoteStringWithSpecialChars } function script:gitTfsShelvesets($filter) { (git tfs shelve-list) | Where-Object { $_ -like "$filter*" } | - ForEach-Object { "'$_'" } + quoteStringWithSpecialChars } function script:gitFiles($filter, $files) { $files | Sort-Object | Where-Object { $_ -like "$filter*" } | - ForEach-Object { if ($_ -like '* *') { "'$_'" } else { $_ } } + quoteStringWithSpecialChars } function script:gitIndex($GitStatus, $filter) { diff --git a/test/Shared.ps1 b/test/Shared.ps1 index 0b07e90a4..0f8f49977 100644 --- a/test/Shared.ps1 +++ b/test/Shared.ps1 @@ -23,6 +23,28 @@ function MakeGitPath([string]$Path) { $Path -replace '\\', '/' } +function NewGitTempRepo { + Push-Location + $temp = [System.IO.Path]::GetTempPath() + $repoPath = Join-Path $temp ([IO.Path]::GetRandomFileName()) + git.exe init $repoPath *>$null + Set-Location $repoPath + $repoPath +} + +function RemoveGitTempRepo($RepoPath) { + Pop-Location + if (Test-Path $repoPath) { + Remove-Item $repoPath -Recurse -Force + } +} + +function ResetGitTempRepoWorkingDir($RepoPath, $Branch = 'master') { + Set-Location $repoPath + git.exe checkout -fq $Branch 2>$null + git.exe clean -xdfq 2>$null +} + # Force the posh-git prompt to be installed. Could be runnng on dev system where # user has customized the prompt. [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] diff --git a/test/TabExpansion.Tests.ps1 b/test/TabExpansion.Tests.ps1 index fe45ec894..f15875fc0 100644 --- a/test/TabExpansion.Tests.ps1 +++ b/test/TabExpansion.Tests.ps1 @@ -120,33 +120,76 @@ Describe 'TabExpansion Tests' { } } } + Context 'Add/Reset/Checkout TabExpansion Tests' { BeforeEach { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] - $origPath = Get-Location - $temp = [System.IO.Path]::GetTempPath() - $repoPath = Join-Path $temp ([IO.Path]::GetRandomFileName()) - - git init $repoPath - Set-Location $repoPath + $repoPath = NewGitTempRepo } AfterEach { - Set-Location $origPath - if (Test-Path $repoPath) { - Remove-Item $repoPath -Recurse -Force - } + RemoveGitTempRepo $repoPath } It 'Tab completes non-ASCII file name' { - git config core.quotepath true # Problematic (default) config + git.exe config core.quotepath true # Problematic (default) config $fileName = "posh$([char]8226)git.txt" - New-Item $fileName + New-Item $fileName -ItemType File - $GitStatus = & $module Get-GitStatus - - $result = & $module GitTabExpansionInternal 'git add ' $GitStatus + $gitStatus = & $module Get-GitStatus + $result = & $module GitTabExpansionInternal 'git add ' $gitStatus $result | Should BeExactly $fileName } } + + Context 'PowerShell Special Chars Tests' { + BeforeAll { + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] + $repoPath = NewGitTempRepo + + 'readme' | Out-File .\README.md -Encoding ascii + git.exe add .\README.md + git.exe commit -m "initial commit." + } + AfterAll { + RemoveGitTempRepo $repoPath + } + AfterEach { + ResetGitTempRepoWorkingDir $repoPath + } + It 'Tab completes branch name with special char as quoted' { + git.exe branch '#develop' 2>$null + + $result = & $module GitTabExpansionInternal 'git checkout #' + $result | Should BeExactly "'#develop'" + } + It 'Tab completes git feature branch name with special char as quoted' { + git.exe branch '#develop' 2>$null + + $result = & $module GitTabExpansionInternal 'git flow feature list #' + $result | Should BeExactly "'#develop'" + } + It 'Tab completes a tag name with special char as quoted' { + $tag = "v1.0.0;abcdef" + git.exe tag $tag + + $result = & $module GitTabExpansionInternal 'git show v1' + $result | Should BeExactly "'$tag'" + } + It 'Tab completes a tag name with single quote correctly' { + git.exe tag "v2.0.0'" + + $result = & $module GitTabExpansionInternal 'git show v2' + $result | Should BeExactly "'v2.0.0'''" + } + It 'Tab completes add file in working dir with special char as quoted' { + $filename = 'foo{bar} (x86).txt'; + New-Item $filename -ItemType File + + $gitStatus = & $module Get-GitStatus + + $result = & $module GitTabExpansionInternal 'git add ' $gitStatus + $result | Should BeExactly "'$filename'" + } + } }