quinjet 0.0.71

A fast, live, keyboard-first Git source-control interface for the terminal
$ErrorActionPreference = "Stop"
Set-StrictMode -Version 3.0

$Root = Split-Path -Parent $PSScriptRoot
$Installer = Join-Path $Root "install.ps1"
$TestRoot = Join-Path ([IO.Path]::GetTempPath()) ("quinjet-installer-tests-" + [Guid]::NewGuid().ToString("N"))
$Fixtures = Join-Path $TestRoot "fixtures"
$DownloadsLog = Join-Path $TestRoot "downloads.log"

function Assert-Equal {
    param(
        [object] $Expected,
        [object] $Actual,
        [string] $Message
    )
    if ($Expected -ne $Actual) {
        throw "${Message}: expected '$Expected', got '$Actual'"
    }
}

function Assert-Contains {
    param(
        [string] $Needle,
        [string] $Path
    )
    if (-not (Select-String -LiteralPath $Path -SimpleMatch $Needle -Quiet)) {
        throw "expected '$Needle' in $Path"
    }
}

function Assert-InstallFailure {
    param(
        [string] $RequestedVersion,
        [string] $Directory,
        [string] $Pattern,
        [string] $Log = (Join-Path $TestRoot "failed-install.log")
    )
    try {
        & $Installer -Version $RequestedVersion -BinDir $Directory -NoModifyPath *> $Log
        throw "installation unexpectedly succeeded"
    }
    catch {
        if ($_.Exception.Message -notlike $Pattern) { throw }
    }
}

function New-ExecutableFixture {
    param([string] $OutputAssembly)

    $compiler = Join-Path $TestRoot "compile-fixture.ps1"
    $compilerSource = @'
param([Parameter(Mandatory)][string] $OutputAssembly)

$source = @"
using System;
using System.IO;

public static class QuinjetInstallerFixture
{
    public static void Main(string[] arguments)
    {
        File.WriteAllText(
            Environment.GetEnvironmentVariable("QUINJET_TEST_COMPLETION_LOG"),
            string.Join(" ", arguments));
    }
}
"@

Add-Type -TypeDefinition $source -OutputAssembly $OutputAssembly -OutputType ConsoleApplication
'@
    [IO.File]::WriteAllText($compiler, $compilerSource)
    $windowsPowerShell = Join-Path $env:SystemRoot "System32\WindowsPowerShell\v1.0\powershell.exe"
    & $windowsPowerShell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File $compiler -OutputAssembly $OutputAssembly
    if ($LASTEXITCODE -ne 0) {
        throw "failed to compile the installer fixture"
    }
}

function Set-ReleaseFixture {
    param(
        [string] $Contents,
        [switch] $Executable,
        [switch] $InvalidChecksum
    )

    $asset = "quinjet-windows-x86_64.exe"
    $assetPath = Join-Path $Fixtures $asset
    if ($Executable) {
        New-ExecutableFixture -OutputAssembly $assetPath
    }
    else {
        [IO.File]::WriteAllText($assetPath, $Contents)
    }
    $hash = if ($InvalidChecksum) { "0" * 64 } else { (Get-FileHash -LiteralPath $assetPath -Algorithm SHA256).Hash }
    [IO.File]::WriteAllText((Join-Path $Fixtures "SHA256SUMS"), "$hash  dist/$asset`n")
}

New-Item -ItemType Directory -Path $Fixtures | Out-Null
[IO.File]::WriteAllText($DownloadsLog, "")

function global:Invoke-WebRequest {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string] $Uri,

        [Parameter()]
        [string] $OutFile,

        [Parameter()]
        [switch] $UseBasicParsing,

        [Parameter()]
        [string] $Method = "Get",

        [Parameter()]
        [int] $TimeoutSec,

        [Parameter()]
        [int] $MaximumRedirection
    )

    Assert-Equal -Expected 30 -Actual $TimeoutSec -Message "request timeout"
    Assert-Equal -Expected "SilentlyContinue" -Actual $ProgressPreference -Message "download progress"
    Add-Content -LiteralPath $global:QuinjetDownloadsLog -Value $Uri
    if ($Method -eq "Head") {
        Assert-Equal -Expected 5 -Actual $MaximumRedirection -Message "redirect limit"
        return [pscustomobject]@{
            BaseResponse = [pscustomobject]@{
                ResponseUri = [Uri] $global:QuinjetLatestUrl
                RequestMessage = [pscustomobject]@{ RequestUri = [Uri] $global:QuinjetLatestUrl }
            }
        }
    }
    if ($Uri -like "*/latest/download/*") {
        throw "asset download was not pinned"
    }
    $asset = [IO.Path]::GetFileName(([Uri] $Uri).AbsolutePath)
    Copy-Item -LiteralPath (Join-Path $global:QuinjetFixtures $asset) -Destination $OutFile
}

$global:QuinjetFixtures = $Fixtures
$global:QuinjetDownloadsLog = $DownloadsLog
$global:QuinjetLatestUrl = "https://github.com/pulkitxm/quinjet/releases/tag/v1.2.3"
$originalInstallDir = $env:QUINJET_INSTALL_DIR
$originalVersion = $env:QUINJET_VERSION
$originalNoModifyPath = $env:QUINJET_NO_MODIFY_PATH
$originalCompletionLog = $env:QUINJET_TEST_COMPLETION_LOG

try {
    Write-Host "test: installs and verifies a pinned Windows release"
    $binDir = Join-Path $TestRoot "successful-install\bin"
    $env:QUINJET_TEST_COMPLETION_LOG = Join-Path $TestRoot "completions.log"
    Set-ReleaseFixture -Executable
    $expectedHash = (Get-FileHash -LiteralPath (Join-Path $Fixtures "quinjet-windows-x86_64.exe") -Algorithm SHA256).Hash
    & $Installer -Version "1.2.3" -BinDir $binDir -NoModifyPath *> (Join-Path $TestRoot "successful-install.log")

    $installed = Join-Path $binDir "quinjet.exe"
    $actualHash = (Get-FileHash -LiteralPath $installed -Algorithm SHA256).Hash
    Assert-Equal -Expected $expectedHash -Actual $actualHash -Message "installed binary hash"
    Assert-Equal -Expected "completions powershell --install --automatic" -Actual ([IO.File]::ReadAllText($env:QUINJET_TEST_COMPLETION_LOG)) -Message "completion installation arguments"
    Assert-Contains -Needle "https://github.com/pulkitxm/quinjet/releases/download/v1.2.3/quinjet-windows-x86_64.exe" -Path $DownloadsLog
    Assert-Contains -Needle "verified SHA-256 checksum" -Path (Join-Path $TestRoot "successful-install.log")

    Write-Host "test: resolves latest once and pins both downloads"
    $downloadCount = (Get-Content -LiteralPath $DownloadsLog).Count
    & $Installer -Version "latest" -BinDir (Join-Path $TestRoot "latest-install\bin") -NoModifyPath *> (Join-Path $TestRoot "latest-install.log")
    Assert-Equal -Expected ($downloadCount + 3) -Actual (Get-Content -LiteralPath $DownloadsLog).Count -Message "pinned latest request count"

    Write-Host "test: rejects invalid latest redirects before fetching assets"
    foreach ($latestUrl in @("https://example.com/releases/tag/v1.2.3", "https://github.com/pulkitxm/quinjet/releases/tag/v1.2.3-beta.1")) {
        $global:QuinjetLatestUrl = $latestUrl
        $downloadCount = (Get-Content -LiteralPath $DownloadsLog).Count
        Assert-InstallFailure -RequestedVersion "latest" -Directory (Join-Path $TestRoot "invalid-latest") -Pattern "invalid latest release*"
        Assert-Equal -Expected ($downloadCount + 1) -Actual (Get-Content -LiteralPath $DownloadsLog).Count -Message "invalid redirect request count"
    }
    $global:QuinjetLatestUrl = "https://github.com/pulkitxm/quinjet/releases/tag/v1.2.3"

    Write-Host "test: rejects invalid checksum records before fetching the binary"
    foreach ($checksumCase in @("duplicate", "missing", "malformed")) {
        Set-ReleaseFixture -Contents "new binary"
        $checksums = Join-Path $Fixtures "SHA256SUMS"
        switch ($checksumCase) {
            "duplicate" { Add-Content -LiteralPath $checksums -Value ([IO.File]::ReadAllText($checksums)) }
            "missing" { [IO.File]::WriteAllText($checksums, (("0" * 64) + "  other.exe`n")) }
            "malformed" { [IO.File]::WriteAllText($checksums, "invalid  quinjet-windows-x86_64.exe`n") }
        }
        $downloadCount = (Get-Content -LiteralPath $DownloadsLog).Count
        Assert-InstallFailure -RequestedVersion "1.2.3" -Directory $binDir -Pattern "the release checksum*"
        Assert-Equal -Expected ($downloadCount + 1) -Actual (Get-Content -LiteralPath $DownloadsLog).Count -Message "invalid checksum request count"
        Assert-Equal -Expected $expectedHash -Actual (Get-FileHash -LiteralPath $installed -Algorithm SHA256).Hash -Message "existing binary preserved"
    }

    Write-Host "test: rejects a checksum mismatch without replacing an installation"
    $binDir = Join-Path $TestRoot "bad-checksum\bin"
    New-Item -ItemType Directory -Path $binDir | Out-Null
    $installed = Join-Path $binDir "quinjet.exe"
    [IO.File]::WriteAllText($installed, "existing binary")
    Set-ReleaseFixture -Contents "tampered binary" -InvalidChecksum

    Assert-InstallFailure -RequestedVersion "latest" -Directory $binDir -Pattern "*checksum verification failed*" -Log (Join-Path $TestRoot "bad-checksum.log")
    Assert-Equal -Expected "existing binary" -Actual ([IO.File]::ReadAllText($installed)) -Message "existing installation"
    Assert-Contains -Needle "https://github.com/pulkitxm/quinjet/releases/download/v1.2.3/quinjet-windows-x86_64.exe" -Path $DownloadsLog

    Write-Host "test: rejects unsafe version values before downloading"
    $downloadCount = (Get-Content -LiteralPath $DownloadsLog).Count
    Assert-InstallFailure -RequestedVersion "v1/../../invalid" -Directory (Join-Path $TestRoot "invalid-version") -Pattern "*invalid release version*"
    Assert-Equal -Expected $downloadCount -Actual (Get-Content -LiteralPath $DownloadsLog).Count -Message "download count"

    Write-Host "All PowerShell installer tests passed."
}
finally {
    $env:QUINJET_INSTALL_DIR = $originalInstallDir
    $env:QUINJET_VERSION = $originalVersion
    $env:QUINJET_NO_MODIFY_PATH = $originalNoModifyPath
    $env:QUINJET_TEST_COMPLETION_LOG = $originalCompletionLog
    Remove-Item Function:\Invoke-WebRequest -Force -ErrorAction SilentlyContinue
    Remove-Variable QuinjetFixtures -Scope Global -ErrorAction SilentlyContinue
    Remove-Variable QuinjetDownloadsLog -Scope Global -ErrorAction SilentlyContinue
    Remove-Variable QuinjetLatestUrl -Scope Global -ErrorAction SilentlyContinue
    Remove-Item -LiteralPath $TestRoot -Recurse -Force -ErrorAction SilentlyContinue
}