psmux 3.3.4

Terminal multiplexer for Windows - tmux alternative for PowerShell and Windows Terminal
# psmux Issue #47 - Running bare `psmux` / `tmux` fails with "no session" error
# Verifies that running psmux with no arguments (bare invocation) correctly
# creates a new session and attaches, rather than erroring out.
#
# The bug: running `tmux` (when tmux is aliased/symlinked to psmux) with no
# arguments gives: Error: Custom { kind: Other, error: "no session" }
#
# This test runs non-interactively and checks:
#   1. Bare `psmux` with no existing session starts a server and creates a session
#   2. After bare invocation, the session exists and is queryable
#   3. The error message "no session" does not appear
#
# Run: pwsh -NoProfile -ExecutionPolicy Bypass -File tests\test_issue47_bare_run.ps1

$ErrorActionPreference = "Continue"
$script:TestsPassed = 0
$script:TestsFailed = 0

function Write-Pass { param($msg) Write-Host "[PASS] $msg" -ForegroundColor Green; $script:TestsPassed++ }
function Write-Fail { param($msg) Write-Host "[FAIL] $msg" -ForegroundColor Red; $script:TestsFailed++ }
function Write-Info { param($msg) Write-Host "[INFO] $msg" -ForegroundColor Cyan }
function Write-Test { param($msg) Write-Host "[TEST] $msg" -ForegroundColor White }

$PSMUX = (Resolve-Path "$PSScriptRoot\..\target\release\psmux.exe" -ErrorAction SilentlyContinue).Path
if (-not $PSMUX) { $PSMUX = (Resolve-Path "$PSScriptRoot\..\target\debug\psmux.exe" -ErrorAction SilentlyContinue).Path }
if (-not $PSMUX) { Write-Error "psmux binary not found. Build first: cargo build --release"; exit 1 }
Write-Info "Using: $PSMUX"

# ============================================================
# SETUP — kill everything so we test from a clean state
# ============================================================
Write-Info "Killing all psmux servers..."
Start-Process -FilePath $PSMUX -ArgumentList "kill-server" -WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
Remove-Item "$env:USERPROFILE\.psmux\*.port" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:USERPROFILE\.psmux\*.key" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:USERPROFILE\.psmux\last_session" -Force -ErrorAction SilentlyContinue

# Verify no sessions exist
$lsBefore = & $PSMUX list-sessions 2>&1 | Out-String
Write-Info "list-sessions before test: $($lsBefore.Trim())"

Write-Host ""
Write-Host ("=" * 60)
Write-Host "  ISSUE #47: BARE INVOCATION ERROR"
Write-Host ("=" * 60)
Write-Host ""

# -----------------------------------------------------------------
# Test 1: Bare invocation should not produce "no session" error
# -----------------------------------------------------------------
Write-Test "1. Bare psmux invocation - should not error with 'no session'"

# We can't run a fully interactive attach in a test script, but we CAN test
# the server-spawn path. Bare `psmux` creates an auto-numbered session (0, 1, 2...)
# like tmux, then attaches to it. We test the server-spawn + naming.

# Use new-session -d to replicate bare behavior (creates auto-numbered session)
& $PSMUX new-session -d 2>&1 | Out-Null
Start-Sleep -Seconds 3

# Check if the port file was created (should be "0" for first session)
$portPath = "$env:USERPROFILE\.psmux\0.port"
if (Test-Path $portPath) {
    Write-Pass "Port file created for auto-numbered session '0'"
    $port = (Get-Content $portPath).Trim()
    Write-Info "  Server port: $port"
} else {
    Write-Fail "Port file NOT created — server may have failed to start"
}

# Check if session is queryable
$hasSession = & $PSMUX has-session -t 0 2>&1 | Out-String
$hasExitCode = $LASTEXITCODE
Write-Info "  has-session exit code: $hasExitCode"
if ($hasExitCode -eq 0) {
    Write-Pass "has-session -t 0 succeeds"
} else {
    Write-Fail "has-session -t 0 failed (exit code $hasExitCode)"
}

# List sessions — should show auto-numbered session
$lsAfter = & $PSMUX list-sessions 2>&1 | Out-String
Write-Info "  list-sessions: $($lsAfter.Trim())"
if ($lsAfter -match "^0:") {
    Write-Pass "Auto-numbered session '0' listed in list-sessions"
} else {
    Write-Fail "Session '0' NOT found in list-sessions"
}

# -----------------------------------------------------------------
# Test 2: Check that client connect to session works (non-interactive)
# -----------------------------------------------------------------
Write-Host ""
Write-Host ("=" * 60)
Write-Host "  TEST 2: CLIENT CAN QUERY EXISTING SESSION"
Write-Host ("=" * 60)

Write-Test "2. display-message works against the default session"

$windowName = & $PSMUX display-message -t default -p '#{window_name}' 2>&1 | Out-String
Write-Info "  window_name: $($windowName.Trim())"
if ($windowName.Trim().Length -gt 0 -and $windowName -notmatch "no session" -and $windowName -notmatch "Error") {
    Write-Pass "display-message returned valid window_name"
} else {
    Write-Fail "display-message failed or returned error: $($windowName.Trim())"
}

# -----------------------------------------------------------------
# Test 3: Error message check — simulate what happens when port file missing
# -----------------------------------------------------------------
Write-Host ""
Write-Host ("=" * 60)
Write-Host "  TEST 3: ERROR MESSAGE FOR MISSING SESSION"
Write-Host ("=" * 60)

Write-Test "3. Commands against non-existent session give clear error"

$errOutput = & $PSMUX display-message -t nonexistent_session_xyz -p '#{window_name}' 2>&1 | Out-String
Write-Info "  Error output: $($errOutput.Trim())"

# The error should be clear, not "Custom { kind: Other, error: ... }"
if ($errOutput -match "Custom.*kind.*Other.*error") {
    Write-Fail "Raw Rust error format exposed to user: $($errOutput.Trim())"
    Write-Info "  Should be a user-friendly message like 'no server running on session ...'"
} else {
    Write-Pass "Error message does not expose raw Rust error format"
}

# The error should mention the session name or "no server"
if ($errOutput -match "no server|session.*not found|can.t find") {
    Write-Pass "Error message is descriptive"
} elseif ($errOutput -match "error|Error") {
    Write-Info "  Error message: $($errOutput.Trim()) — review if user-friendly enough"
    Write-Pass "Error reported (may need friendlier message)"
} else {
    Write-Info "  Output: $($errOutput.Trim())"
}

# -----------------------------------------------------------------
# Test 4: Bare invocation with rename (tmux aliased) — the actual issue #47
# -----------------------------------------------------------------
Write-Host ""
Write-Host ("=" * 60)
Write-Host "  TEST 4: SIMULATE BARE INVOCATION (tmux -> psmux)"
Write-Host ("=" * 60)

Write-Test "4. Running psmux with no args — should create auto-numbered session (tmux-compatible)"

# Kill all sessions first
& $PSMUX kill-server 2>$null | Out-Null
Start-Sleep -Seconds 2
Remove-Item "$env:USERPROFILE\.psmux\*.port" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:USERPROFILE\.psmux\*.key" -Force -ErrorAction SilentlyContinue

# Now run psmux with no arguments in a subprocess with a timeout
# This will try to create + attach interactively; we kill it after a few seconds
# and check if a port file was created (server started)
$proc = Start-Process -FilePath $PSMUX -PassThru -WindowStyle Hidden
Start-Sleep -Seconds 5

# Check if an auto-numbered session was created (should be "0")
$portExists = Test-Path "$env:USERPROFILE\.psmux\0.port"
Write-Info "  Port file exists after bare invocation: $portExists"

if ($portExists) {
    Write-Pass "Bare invocation created auto-numbered session '0' — no 'no session' error"
    # Verify session is live
    $check = & $PSMUX has-session -t 0 2>&1 | Out-String
    if ($LASTEXITCODE -eq 0) {
        Write-Pass "Session '0' is alive after bare invocation"
    } else {
        Write-Fail "Session '0' port file exists but session not responding"
    }
} else {
    # Check if any numeric port file exists (warm server might have been claimed with a different number)
    $anyPort = Get-ChildItem "$env:USERPROFILE\.psmux\*.port" -ErrorAction SilentlyContinue | Where-Object { $_.BaseName -match '^\d+$' -and $_.BaseName -ne '__warm__' }
    if ($anyPort) {
        Write-Pass "Bare invocation created auto-numbered session '$($anyPort[0].BaseName)'"
    } else {
        Write-Fail "Bare invocation did NOT create a session — may error with 'no session' (issue #47)"
    }
}

# Kill the process if still running
if (-not $proc.HasExited) {
    $proc.Kill()
    Start-Sleep -Milliseconds 500
}

# ============================================================
# CLEANUP
# ============================================================
Write-Host ""
Write-Info "Cleaning up..."
& $PSMUX kill-server 2>$null | Out-Null
Start-Sleep -Seconds 1

Write-Host ""
Write-Host ("=" * 60)
Write-Host "  RESULTS: $($script:TestsPassed) passed, $($script:TestsFailed) failed"
Write-Host ("=" * 60)

if ($script:TestsFailed -gt 0) {
    Write-Host "Some tests FAILED — issue #47 may be present" -ForegroundColor Red
    exit 1
} else {
    Write-Host "All tests PASSED" -ForegroundColor Green
    exit 0
}