diff --git a/src/core/handlers.ps1 b/src/core/handlers.ps1 index 0eae8d0d..1aa79f9c 100644 --- a/src/core/handlers.ps1 +++ b/src/core/handlers.ps1 @@ -120,10 +120,10 @@ function Invoke-List { function Invoke-Install { param ($arguments) - $version = $arguments[0] $arch = Resolve-Arch -arguments $arguments $buildType = Resolve-BuildType -arguments $arguments + $version = $arguments[0] if ($version -eq 'auto') { $result = Select-PHPVersionAutomatically if (-not $result.version) { @@ -136,24 +136,40 @@ function Invoke-Install { return -1 } - $version = $result.version - } elseif ($version -eq 'latest') { + return (Install-PHP -version $result.version -arch $arch -buildType $buildType) + } + + if ($version -eq 'latest') { $latestVersion = Get-LatestPHPVersion -arch $arch -buildType $buildType if (-not $latestVersion) { Show-Error -message "`nFailed to find the latest PHP version" return -1 } - $version = $latestVersion.version - Show-Message -message "`nLatest available PHP version is $version" + if (-not $latestVersion.version) { + Show-Warning -message "`nPlease provide a PHP version to install" + return -1 + } + + Show-Message -message "`nLatest available PHP version is $($latestVersion.version)" + + return (Install-PHP -version $latestVersion.version -arch $arch -buildType $buildType) } - if (-not $version) { + $versions = Resolve-VersionsFromArguments -arguments $arguments + + if ($versions.Count -eq 0) { Show-Warning -message "`nPlease provide a PHP version to install" return -1 } - return (Install-PHP -version $version -arch $arch -buildType $buildType) + $codes = @() + foreach ($version in $versions) { + $codes += Install-PHP -version $version -arch $arch -buildType $buildType + } + + if ($codes | Where-Object -FilterScript { $_ -ne 0 }) { return -1 } + return 0 } function Invoke-Use { @@ -187,17 +203,24 @@ function Invoke-Use { function Invoke-Uninstall { param ($arguments) - $version = $arguments[0] + $versions = Resolve-VersionsFromArguments -arguments $arguments - if (-not $version) { + if ($versions.Count -eq 0) { Show-Warning -message "`nPlease provide a PHP version to uninstall" return -1 } - $remainingArgs = if ($arguments.Count -gt 1) { $arguments[1..($arguments.Count - 1)] } else { @() } + $remainingArgs = $arguments | Where-Object -FilterScript { $_ -notin $versions } $skipConfirmation = [bool]($remainingArgs | Where-Object -FilterScript { @('-y', '--yes') -contains $_ } | Select-Object -First 1) - return (Uninstall-PHP -version $version -skipConfirmation $skipConfirmation) + $results = @() + foreach ($version in $versions) { + $result = Uninstall-PHP -version $version -skipConfirmation $skipConfirmation + $results += $result + } + + if ($results | Where-Object -FilterScript { $_ -ne 0 }) { return -1 } + return 0 } function Invoke-Ini { diff --git a/src/helpers/args.ps1 b/src/helpers/args.ps1 index 8945efe3..eca8fd8c 100644 --- a/src/helpers/args.ps1 +++ b/src/helpers/args.ps1 @@ -1,4 +1,4 @@ - + function Resolve-Alias { param ($alias) @@ -65,3 +65,11 @@ function Resolve-Arch { return $arch } + +function Resolve-VersionsFromArguments { + param ($arguments) + + $versions = $arguments | Where-Object -FilterScript { $_ -match '^\d+(\.\d+){0,2}$' } + + return $versions +} diff --git a/tests/core/handlers.tests.ps1 b/tests/core/handlers.tests.ps1 index d6575ca4..ea6fb37d 100644 --- a/tests/core/handlers.tests.ps1 +++ b/tests/core/handlers.tests.ps1 @@ -259,10 +259,9 @@ Describe "Invoke-Install" { } It "Should install detected PHP version from the project" { - $arguments = @('auto') + Mock Select-PHPVersionAutomatically { return @{ code = -1; version = '8.1' } } - Mock Get-MatchingPHPVersions { return @() } - Mock Find-PHPVersionFromProject { return '8.1' } + $arguments = @('auto') $result = Invoke-Install -arguments $arguments $result | Should -Be 0 @@ -309,6 +308,86 @@ Describe "Invoke-Install" { $result | Should -Be -1 } + + It "Should resturn -1 when version property is null and displays a warning message" { + $arguments = @('latest') + Mock Get-LatestPHPVersion { return @{version = $null } } + + $result = Invoke-Install -arguments $arguments + + $result | Should -Be -1 + Should -Invoke Show-Warning -ParameterFilter { $message -like '*Please provide a PHP version to install*' } + } + + It "Should return -1 when detected PHP version is already installed" { + Mock Select-PHPVersionAutomatically { return @{ code = 0; version = '8.2' } } + + $arguments = @('auto') + $result = Invoke-Install -arguments $arguments + + $result | Should -Be -1 + } + + It "Should install multiple PHP versions when multiple versions are provided" { + $arguments = @('8.2.0', '8.3.0', '8.1.0') + Mock Install-PHP { return 0 } + + $result = Invoke-Install -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Install-PHP -Times 3 + } + + It "Should install each version with correct parameters when multiple versions are provided" { + $arguments = @('8.2.0', '8.3.0') + Mock Install-PHP { return 0 } + + $result = Invoke-Install -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Install-PHP -Times 1 -ParameterFilter { $version -eq '8.2.0' } + Should -Invoke Install-PHP -Times 1 -ParameterFilter { $version -eq '8.3.0' } + } + + It "Should return -1 when any version installation fails in multiple versions" { + $arguments = @('8.2.0', '8.3.0') + Mock Install-PHP { return 0 } + Mock Install-PHP { return -1 } -ParameterFilter { $version -eq '8.3.0' } + + $result = Invoke-Install -arguments $arguments + $result | Should -Be -1 + } + + It "Should continue installing remaining versions even if one fails" { + $arguments = @('8.2.0', '8.3.0', '8.1.0') + Mock Install-PHP { return 0 } + Mock Install-PHP { return -1 } -ParameterFilter { $version -eq '8.3.0' } + + $result = Invoke-Install -arguments $arguments + $result | Should -Be -1 + + Should -Invoke Install-PHP -Times 3 + } + + It "Should handle multiple versions with arch and buildType flags" { + $arguments = @('8.2.0', '8.3.0', 'x64', 'ts') + Mock Install-PHP { return 0 } + + $result = Invoke-Install -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Install-PHP -Times 2 -ParameterFilter { $arch -eq 'x64' -and $buildType -eq 'ts' } + } + + It "Should filter out non-version arguments when installing multiple versions" { + $arguments = @('8.2.0', '--flag', '8.3.0', '--another-flag') + Mock Install-PHP { return 0 } + + $result = Invoke-Install -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Install-PHP -Times 2 + } } Describe "Invoke-Use" { @@ -424,6 +503,87 @@ Describe "Invoke-Uninstall" { $version -eq '8.2.0' -and $skipConfirmation -eq $false } } + + It "Should uninstall multiple PHP versions when multiple versions are provided" { + $arguments = @('8.2.0', '8.3.0', '8.1.0') + Mock Uninstall-PHP { return 0 } + + $result = Invoke-Uninstall -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Uninstall-PHP -Times 3 + } + + It "Should uninstall each version with correct parameters when multiple versions are provided" { + $arguments = @('8.2.0', '8.3.0') + Mock Uninstall-PHP { return 0 } + + $result = Invoke-Uninstall -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Uninstall-PHP -Times 1 -ParameterFilter { $version -eq '8.2.0' } + Should -Invoke Uninstall-PHP -Times 1 -ParameterFilter { $version -eq '8.3.0' } + } + + It "Should return -1 when any version uninstall fails in multiple versions" { + $arguments = @('8.2.0', '8.3.0') + Mock Uninstall-PHP { return 0 } + Mock Uninstall-PHP { return -1 } -ParameterFilter { $version -eq '8.3.0' } + + $result = Invoke-Uninstall -arguments $arguments + $result | Should -Be -1 + } + + It "Should continue uninstalling remaining versions even if one fails" { + $arguments = @('8.2.0', '8.3.0', '8.1.0') + Mock Uninstall-PHP { return 0 } + Mock Uninstall-PHP { return -1 } -ParameterFilter { $version -eq '8.3.0' } + + $result = Invoke-Uninstall -arguments $arguments + $result | Should -Be -1 + + Should -Invoke Uninstall-PHP -Times 3 + } + + It "Should pass skipConfirmation true to all versions when -y flag is provided with multiple versions" { + $arguments = @('8.2.0', '8.3.0', '-y') + Mock Uninstall-PHP { return 0 } + + $result = Invoke-Uninstall -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Uninstall-PHP -Times 2 -ParameterFilter { $skipConfirmation -eq $true } + } + + It "Should pass skipConfirmation true to all versions when --yes flag is provided with multiple versions" { + $arguments = @('8.2.0', '8.3.0', '--yes') + Mock Uninstall-PHP { return 0 } + + $result = Invoke-Uninstall -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Uninstall-PHP -Times 2 -ParameterFilter { $skipConfirmation -eq $true } + } + + It "Should filter out non-version arguments when uninstalling multiple versions" { + $arguments = @('8.2.0', '--flag', '8.3.0', '--another-flag') + Mock Uninstall-PHP { return 0 } + + $result = Invoke-Uninstall -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Uninstall-PHP -Times 2 + } + + It "Should handle mixed version and flag arguments correctly" { + $arguments = @('8.2.0', '-y', '8.3.0', '--force') + Mock Uninstall-PHP { return 0 } + + $result = Invoke-Uninstall -arguments $arguments + $result | Should -Be 0 + + Should -Invoke Uninstall-PHP -Times 2 -ParameterFilter { $skipConfirmation -eq $true } + } } Describe "Invoke-Ini" { diff --git a/tests/helpers/args.tests.ps1 b/tests/helpers/args.tests.ps1 index 981e155c..6f2cbc5a 100644 --- a/tests/helpers/args.tests.ps1 +++ b/tests/helpers/args.tests.ps1 @@ -237,3 +237,108 @@ Describe "Resolve-Arch" { } } } + +Describe "Resolve-VersionsFromArguments" { + Context "Basic version extraction" { + It "Returns single version when one version is provided" { + $arguments = @('8.2.0') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8.2.0') + } + + It "Returns multiple versions when multiple versions are provided" { + $arguments = @('8.2.0', '8.3.0', '8.1.0') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8.2.0', '8.3.0', '8.1.0') + } + + It "Returns empty array when no versions are provided" { + $arguments = @('some', 'other', 'args') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -BeNullOrEmpty + } + + It "Returns empty array when arguments array is empty" { + $arguments = @() + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -BeNullOrEmpty + } + + It "Returns null when arguments is null" { + $result = Resolve-VersionsFromArguments -arguments $null + $result | Should -BeNullOrEmpty + } + } + + Context "Version format validation" { + It "Extracts version with two parts (major.minor)" { + $arguments = @('8.2') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8.2') + } + + It "Extracts version with one part (major)" { + $arguments = @('8') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8') + } + + It "Extracts version with three parts (major.minor.patch)" { + $arguments = @('8.2.15') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8.2.15') + } + + It "Filters out non-version arguments" { + $arguments = @('8.2.0', 'some-flag', '8.3.0', '--another-flag', '8.1.0') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8.2.0', '8.3.0', '8.1.0') + } + + It "Filters out arguments with special characters" { + $arguments = @('8.2.0', 'latest', 'auto', '--flag') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8.2.0') + } + + It "Filters out arguments with letters" { + $arguments = @('8.2.0', 'abc', '8.3.0', 'def') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8.2.0', '8.3.0') + } + + It "Filters out arguments with dots and letters" { + $arguments = @('8.2.0', '8.2.0rc1', '8.3.0beta') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8.2.0') + } + } + + Context "Mixed arguments" { + It "Extracts versions from mixed valid and invalid arguments" { + $arguments = @('--arch', 'x64', '8.2.0', '--build', 'ts', '8.3.0') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('8.2.0', '8.3.0') + } + + It "Maintains order of versions as they appear in arguments" { + $arguments = @('8.1.0', '8.2.0', '8.3.0') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result[0] | Should -Be '8.1.0' + $result[1] | Should -Be '8.2.0' + $result[2] | Should -Be '8.3.0' + } + + It "Handles single digit versions" { + $arguments = @('7', '8') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('7', '8') + } + + It "Handles versions with leading zeros" { + $arguments = @('08.02.00', '08.03.00') + $result = Resolve-VersionsFromArguments -arguments $arguments + $result | Should -Be @('08.02.00', '08.03.00') + } + } +}