Tests/Public/Install-PWSHYBKPIVTool.Tests.ps1

BeforeAll {
    Import-Module (Resolve-Path "$PSScriptRoot\..\..\Posh-YBKPIV.psd1") -Force

    $testJson = @'
{
  "version": "1.0",
  "installation": {
    "urlTemplate": "https://developers.yubico.com/yubico-piv-tool/Releases/yubico-piv-tool-{version}-{arch}.msi",
    "version": "2.7.3",
    "architecture": "win64",
    "installPath": "C:\\Program Files\\Yubico\\Yubico PIV Tool\\bin\\yubico-piv-tool.exe",
    "installPathWow6432": "C:\\Program Files (x86)\\Yubico\\Yubico PIV Tool\\bin\\yubico-piv-tool.exe"
  },
  "Logging": { "Enabled": false }
}
'@

    $script:TestConfigPath = [IO.Path]::GetTempFileName()
    Set-Content -Path $script:TestConfigPath -Value $testJson -Encoding UTF8
    InModuleScope Posh-YBKPIV -Parameters @{ ConfigPath = $script:TestConfigPath } {
        param($ConfigPath)
        $script:ConfigPath = $ConfigPath
    }
}

AfterAll {
    Remove-Item -Path $script:TestConfigPath -ErrorAction SilentlyContinue
    Remove-Module Posh-YBKPIV -ErrorAction SilentlyContinue
}

Describe 'Install-PWSHYBKPIVTool' -Tag Unit {
    BeforeEach {
        $script:InstallExePath = 'C:\Program Files\Yubico\Yubico PIV Tool\bin\yubico-piv-tool.exe'
        # Only the install-path existence check is mocked; Test-Path calls for anything else
        # (e.g. Read-PWSHYBKPIVConfigFile's check on $script:ConfigPath) run for real.
        Mock -ModuleName Posh-YBKPIV Test-Path { $false } -ParameterFilter { $Path -eq $script:InstallExePath }
        Mock -ModuleName Posh-YBKPIV Test-PWSHYBKPIVElevated { $true }
        Mock -ModuleName Posh-YBKPIV Save-PWSHYBKPIVDownloadFile {}
        Mock -ModuleName Posh-YBKPIV Invoke-PWSHYBKPIVMsiInstall {}
        Mock -ModuleName Posh-YBKPIV Remove-Item {}
    }

    Context 'When yubico-piv-tool.exe is already installed' {
        It 'Skips download and install, and returns the existing path' {
            Mock -ModuleName Posh-YBKPIV Test-Path { $true } -ParameterFilter { $Path -eq $script:InstallExePath }
            $result = Install-PWSHYBKPIVTool -Confirm:$false
            $result | Should -Be $script:InstallExePath
            Should -Invoke -ModuleName Posh-YBKPIV Save-PWSHYBKPIVDownloadFile -Times 0
            Should -Invoke -ModuleName Posh-YBKPIV Invoke-PWSHYBKPIVMsiInstall -Times 0
        }

        It 'Reinstalls anyway when -Force is specified' {
            Mock -ModuleName Posh-YBKPIV Test-Path { $true } -ParameterFilter { $Path -eq $script:InstallExePath }
            Install-PWSHYBKPIVTool -Force -Confirm:$false
            Should -Invoke -ModuleName Posh-YBKPIV Save-PWSHYBKPIVDownloadFile -Times 1
            Should -Invoke -ModuleName Posh-YBKPIV Invoke-PWSHYBKPIVMsiInstall -Times 1
        }
    }

    Context 'When not installed and the session is not elevated' {
        It 'Throws a clear error and does not attempt to download' {
            Mock -ModuleName Posh-YBKPIV Test-PWSHYBKPIVElevated { $false }
            { Install-PWSHYBKPIVTool -Confirm:$false } | Should -Throw -ExpectedMessage '*elevated*'
            Should -Invoke -ModuleName Posh-YBKPIV Save-PWSHYBKPIVDownloadFile -Times 0
        }
    }

    Context 'When not installed and the session is elevated' {
        It 'Downloads and installs, then returns the resolved install path' {
            # First check (pre-install): not present. Second check (post-install): present.
            $script:callCount = 0
            Mock -ModuleName Posh-YBKPIV Test-Path -ParameterFilter { $Path -eq $script:InstallExePath } -MockWith {
                $script:callCount++
                $script:callCount -gt 1
            }

            $result = Install-PWSHYBKPIVTool -Confirm:$false
            $result | Should -Be $script:InstallExePath
            Should -Invoke -ModuleName Posh-YBKPIV Save-PWSHYBKPIVDownloadFile -Times 1
            Should -Invoke -ModuleName Posh-YBKPIV Invoke-PWSHYBKPIVMsiInstall -Times 1
        }

        It 'Throws when the exe is still missing after msiexec reports success' {
            { Install-PWSHYBKPIVTool -Confirm:$false } | Should -Throw -ExpectedMessage '*was not found*'
        }

        It 'Does not download or install when -WhatIf is used' {
            Install-PWSHYBKPIVTool -WhatIf
            Should -Invoke -ModuleName Posh-YBKPIV Save-PWSHYBKPIVDownloadFile -Times 0
            Should -Invoke -ModuleName Posh-YBKPIV Invoke-PWSHYBKPIVMsiInstall -Times 0
        }

        It 'Removes the temporary MSI file afterward' {
            $script:callCount = 0
            Mock -ModuleName Posh-YBKPIV Test-Path -ParameterFilter { $Path -eq $script:InstallExePath } -MockWith {
                $script:callCount++
                $script:callCount -gt 1
            }
            Install-PWSHYBKPIVTool -Confirm:$false
            Should -Invoke -ModuleName Posh-YBKPIV Remove-Item -Times 1
        }
    }
}