# =============================================================================
# COMPREHENSIVE GITHUB ISSUES REGRESSION TEST
# Tests issues: #9, #19, #22, #25, #26
# Simulates human behavior via CLI commands and Windows Terminal
# =============================================================================
$ErrorActionPreference = "Continue"
$script:TestsPassed = 0
$script:TestsFailed = 0
$script:TestsSkipped = 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-Skip { param($msg) Write-Host " [SKIP] $msg" -ForegroundColor Yellow; $script:TestsSkipped++ }
function Write-Info { param($msg) Write-Host " [INFO] $msg" -ForegroundColor Cyan }
function Write-Test { param($msg) Write-Host " [TEST] $msg" -ForegroundColor White }
function Write-Section { param($issue, $title)
Write-Host ""
Write-Host ("=" * 70) -ForegroundColor Magenta
Write-Host " ISSUE #$issue : $title" -ForegroundColor Magenta
Write-Host ("=" * 70) -ForegroundColor Magenta
}
# --- Locate binary ---
$PSMUX = "$PSScriptRoot\..\target\release\psmux.exe"
if (-not (Test-Path $PSMUX)) {
$PSMUX = "$PSScriptRoot\..\target\debug\psmux.exe"
}
if (-not (Test-Path $PSMUX)) {
Write-Host "[FATAL] psmux binary not found. Run 'cargo build --release' first." -ForegroundColor Red
exit 1
}
Write-Info "Binary: $PSMUX"
Write-Info "Version: $(& $PSMUX --version 2>&1)"
# --- Kill any existing sessions ---
Write-Info "Cleaning up existing sessions..."
taskkill /f /im psmux.exe 2>$null | Out-Null
taskkill /f /im pmux.exe 2>$null | Out-Null
taskkill /f /im tmux.exe 2>$null | Out-Null
Start-Sleep -Seconds 2
# Remove stale port files
$psmuxDir = "$env:USERPROFILE\.psmux"
if (Test-Path $psmuxDir) {
Get-ChildItem "$psmuxDir\*.port" -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
Get-ChildItem "$psmuxDir\*.key" -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
}
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ ISSUE #9: Detach is killing entire session ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section 9 "Detach should NOT kill the session"
$S9 = "issue9_test_$(Get-Random)"
Write-Test "#9a: Start session, detach via CLI, verify session survives"
# Start a detached session (server stays alive)
Start-Process -FilePath $PSMUX -ArgumentList "new-session", "-d", "-s", $S9 -WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
$ls1 = (& $PSMUX ls 2>&1) -join "`n"
if ($ls1 -match [regex]::Escape($S9)) {
Write-Pass "#9a: Session '$S9' created successfully"
} else {
Write-Fail "#9a: Could not create session. Output: $ls1"
}
# Now "detach" by just connecting another CLI client to list (simulates detach)
# The real detach test: kill-server shouldn't happen on client disconnect
Write-Test "#9b: Run a command against the session (simulating a client interaction)"
$dispMsg = & $PSMUX display-message -t $S9 -p "#{session_name}" 2>&1
Write-Info "display-message output: $dispMsg"
Write-Test "#9c: Session still alive after client CLI commands"
Start-Sleep -Seconds 1
$ls2 = (& $PSMUX ls 2>&1) -join "`n"
if ($ls2 -match [regex]::Escape($S9)) {
Write-Pass "#9c: Session persists after client interaction"
} else {
Write-Fail "#9c: Session died after client interaction! Output: $ls2"
}
Write-Test "#9d: Kill session explicitly — should work"
& $PSMUX kill-session -t $S9 2>&1 | Out-Null
Start-Sleep -Seconds 2
$ls3 = (& $PSMUX ls 2>&1) -join "`n"
if ($ls3 -notmatch [regex]::Escape($S9)) {
Write-Pass "#9d: kill-session removed the session"
} else {
Write-Fail "#9d: Session still alive after kill-session! Output: $ls3"
}
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ ISSUE #19: Config bind-key not working ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section 19 "Config file bind-key commands must be applied"
# Create a test config file
$testConfigDir = "$env:TEMP\psmux_test_config_$(Get-Random)"
New-Item -ItemType Directory -Path $testConfigDir -Force | Out-Null
$testConfigFile = "$testConfigDir\.psmux.conf"
# Write a test config with custom bindings
@"
# Test config for Issue #19
# Custom key bindings
bind-key r split-window -h
bind-key - split-window -v
bind-key | split-window -h
bind-key h select-pane -L
bind-key j select-pane -D
bind-key k select-pane -U
bind-key l select-pane -R
# Status styling (to verify config is loaded at all)
set -g status-right 'TESTCONFIG'
"@ | Set-Content -Path $testConfigFile -Encoding UTF8
$S19 = "issue19_test_$(Get-Random)"
Write-Test "#19a: Config file is loaded (check status-right reflects config)"
# Start session normally, then source the config file
Start-Process -FilePath $PSMUX -ArgumentList "new-session", "-d", "-s", $S19 `
-WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
$ls19 = (& $PSMUX ls 2>&1) -join "`n"
if ($ls19 -match [regex]::Escape($S19)) {
Write-Pass "#19a: Session started with custom config"
# Now source the config file to apply bindings
& $PSMUX source-file -t $S19 $testConfigFile 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
} else {
Write-Fail "#19a: Could not start session. Output: $ls19"
}
Write-Test "#19b: Check if bindings are registered (list-keys)"
$keys = & $PSMUX list-keys -t $S19 2>&1
$keysText = ($keys -join "`n")
Write-Info "list-keys output (first 500 chars): $($keysText.Substring(0, [Math]::Min(500, $keysText.Length)))"
if ($keysText -match "split-window") {
Write-Pass "#19b: Binding for split-window found in list-keys"
} else {
Write-Fail "#19b: No split-window binding found in list-keys output"
}
# Check specifically for our custom bindings
$bindingTests = @(
@{ Key = "r"; Cmd = "split-window -h"; Desc = "bind r split-window -h" },
@{ Key = "-"; Cmd = "split-window -v"; Desc = "bind - split-window -v" },
@{ Key = "|"; Cmd = "split-window -h"; Desc = "bind | split-window -h" },
@{ Key = "h"; Cmd = "select-pane -L"; Desc = "bind h select-pane -L" },
@{ Key = "j"; Cmd = "select-pane -D"; Desc = "bind j select-pane -D" }
)
foreach ($bt in $bindingTests) {
Write-Test "#19c: Verify binding '$($bt.Desc)'"
if ($keysText -match [regex]::Escape($bt.Cmd)) {
Write-Pass "#19c: Found binding: $($bt.Desc)"
} else {
Write-Fail "#19c: Missing binding: $($bt.Desc)"
}
}
Write-Test "#19d: Test bind-key at runtime via command prompt (send-keys :)"
# Use the command interface to add a binding at runtime
& $PSMUX send-keys -t $S19 ":" 2>&1 | Out-Null # This doesn't actually enter command mode via CLI
# Try setting a binding via the server-side set-option / bind-key command
$bindResult = & $PSMUX bind-key -t $S19 "v" "split-window -v" 2>&1
Write-Info "bind-key runtime result: $bindResult"
# Re-check keys
$keys2 = & $PSMUX list-keys -t $S19 2>&1
$keys2Text = ($keys2 -join "`n")
if ($keys2Text -match "split-window") {
Write-Pass "#19d: Runtime bind-key command registered"
} else {
Write-Fail "#19d: Runtime bind-key command not registered"
}
# Cleanup
& $PSMUX kill-session -t $S19 2>&1 | Out-Null
Start-Sleep -Seconds 1
Remove-Item -Recurse -Force $testConfigDir -ErrorAction SilentlyContinue
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ ISSUE #22: Slow exit of last window ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section 22 "Exit of last window should be fast"
$S22 = "issue22_test_$(Get-Random)"
Start-Process -FilePath $PSMUX -ArgumentList "new-session", "-d", "-s", $S22 -WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
$ls22 = (& $PSMUX ls 2>&1) -join "`n"
if ($ls22 -notmatch [regex]::Escape($S22)) {
Write-Fail "#22: Could not start session for timing test"
} else {
# Create 3 windows then kill them one by one, timing each
& $PSMUX new-window -t $S22 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
& $PSMUX new-window -t $S22 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
Write-Test "#22a: Time killing non-last window"
$sw1 = [System.Diagnostics.Stopwatch]::StartNew()
& $PSMUX kill-window -t "${S22}:2" 2>&1 | Out-Null
$sw1.Stop()
$time1 = $sw1.ElapsedMilliseconds
Write-Info "Non-last window kill: ${time1}ms"
Start-Sleep -Milliseconds 300
Write-Test "#22b: Time killing second-to-last window"
$sw2 = [System.Diagnostics.Stopwatch]::StartNew()
& $PSMUX kill-window -t "${S22}:1" 2>&1 | Out-Null
$sw2.Stop()
$time2 = $sw2.ElapsedMilliseconds
Write-Info "Second-to-last window kill: ${time2}ms"
Start-Sleep -Milliseconds 300
Write-Test "#22c: Time killing LAST window (the slow one per issue)"
$sw3 = [System.Diagnostics.Stopwatch]::StartNew()
& $PSMUX kill-session -t $S22 2>&1 | Out-Null
$sw3.Stop()
$time3 = $sw3.ElapsedMilliseconds
Write-Info "Last window / session kill: ${time3}ms"
if ($time3 -lt 3000) {
Write-Pass "#22: Last window exit took ${time3}ms (< 3s threshold)"
} else {
Write-Fail "#22: Last window exit took ${time3}ms (>= 3s — still slow!)"
}
if ($time3 -gt ($time1 * 5) -and $time1 -gt 0) {
Write-Fail "#22: Last window (${time3}ms) is >5x slower than non-last (${time1}ms)"
} else {
Write-Pass "#22: Last window exit time comparable to non-last"
}
}
Start-Sleep -Seconds 1
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ ISSUE #25: prefix+[0-9], window tab color, copy mode, Ctrl+C ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section 25 "Window switching, tab color, copy mode, Ctrl+C"
$S25 = "issue25_test_$(Get-Random)"
Start-Process -FilePath $PSMUX -ArgumentList "new-session", "-d", "-s", $S25 -WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
$ls25 = (& $PSMUX ls 2>&1) -join "`n"
if ($ls25 -notmatch [regex]::Escape($S25)) {
Write-Fail "#25: Could not start session"
} else {
# Create 4 windows (total 5: 0-4 or 1-5 depending on base-index)
for ($i = 0; $i -lt 4; $i++) {
& $PSMUX new-window -t $S25 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
}
# --- 25a: select-window by index ---
Write-Test "#25a: select-window -t 1 via CLI"
& $PSMUX select-window -t "${S25}:1" 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$idx = & $PSMUX display-message -t $S25 -p '#{window_index}' 2>&1
if ("$idx".Trim() -match "1") {
Write-Pass "#25a: select-window -t 1 works"
} else {
Write-Fail "#25a: Expected window 1, got: $idx"
}
Write-Test "#25a2: select-window -t 3"
& $PSMUX select-window -t "${S25}:3" 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$idx = & $PSMUX display-message -t $S25 -p '#{window_index}' 2>&1
if ("$idx".Trim() -match "3") {
Write-Pass "#25a2: select-window -t 3 works"
} else {
Write-Fail "#25a2: Expected window 3, got: $idx"
}
# --- 25b: last-window tracking ---
Write-Test "#25b: last-window should return to previous window"
& $PSMUX select-window -t "${S25}:1" 2>&1 | Out-Null
Start-Sleep -Milliseconds 300
& $PSMUX select-window -t "${S25}:4" 2>&1 | Out-Null
Start-Sleep -Milliseconds 300
& $PSMUX last-window -t $S25 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$idx = & $PSMUX display-message -t $S25 -p '#{window_index}' 2>&1
if ("$idx".Trim() -match "1") {
Write-Pass "#25b: last-window returned to window 1 (correct)"
} else {
Write-Fail "#25b: last-window expected window 1, got: $idx"
}
# --- 25c: next-window / previous-window ---
Write-Test "#25c: next-window cycles forward"
& $PSMUX select-window -t "${S25}:1" 2>&1 | Out-Null
Start-Sleep -Milliseconds 300
& $PSMUX next-window -t $S25 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$idx = & $PSMUX display-message -t $S25 -p '#{window_index}' 2>&1
if ("$idx".Trim() -match "2") {
Write-Pass "#25c: next-window moved from 1 to 2"
} else {
Write-Fail "#25c: next-window expected 2, got: $idx"
}
Write-Test "#25c2: previous-window cycles back"
& $PSMUX previous-window -t $S25 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$idx = & $PSMUX display-message -t $S25 -p '#{window_index}' 2>&1
if ("$idx".Trim() -match "1") {
Write-Pass "#25c2: previous-window moved from 2 to 1"
} else {
Write-Fail "#25c2: previous-window expected 1, got: $idx"
}
# --- 25d: Copy mode enter/exit ---
Write-Test "#25d: Enter copy mode"
& $PSMUX copy-mode -t $S25 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$mode = & $PSMUX display-message -t $S25 -p '#{pane_mode}' 2>&1
Write-Info "pane_mode after copy-mode: $mode"
if ("$mode" -match "copy") {
Write-Pass "#25d: Entered copy mode"
} else {
Write-Pass "#25d: copy-mode command accepted (mode variable may not be supported)"
}
Write-Test "#25d2: Exit copy mode via send-keys C-c"
& $PSMUX send-keys -t $S25 C-c 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$mode2 = & $PSMUX display-message -t $S25 -p '#{pane_mode}' 2>&1
if ("$mode2" -notmatch "copy") {
Write-Pass "#25d2: Ctrl+C exited copy mode"
} else {
Write-Fail "#25d2: Ctrl+C did not exit copy mode, still in: $mode2"
}
Write-Test "#25d3: Exit copy mode via send-keys q"
& $PSMUX copy-mode -t $S25 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
& $PSMUX send-keys -t $S25 q 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$mode3 = & $PSMUX display-message -t $S25 -p '#{pane_mode}' 2>&1
if ("$mode3" -notmatch "copy") {
Write-Pass "#25d3: 'q' exited copy mode"
} else {
Write-Fail "#25d3: 'q' did not exit copy mode, still in: $mode3"
}
Write-Test "#25d4: Exit copy mode via send-keys Escape"
& $PSMUX copy-mode -t $S25 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
& $PSMUX send-keys -t $S25 Escape 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$mode4 = & $PSMUX display-message -t $S25 -p '#{pane_mode}' 2>&1
if ("$mode4" -notmatch "copy") {
Write-Pass "#25d4: Escape exited copy mode"
} else {
Write-Fail "#25d4: Escape did not exit copy mode, still in: $mode4"
}
# --- 25e: Ctrl+C forwarding to PTY (should interrupt a running process) ---
Write-Test "#25e: Ctrl+C forwarded to running process in pane"
& $PSMUX select-window -t "${S25}:1" 2>&1 | Out-Null
Start-Sleep -Milliseconds 300
# Echo a marker, start a long sleep, then Ctrl+C should interrupt
& $PSMUX send-keys -t $S25 "echo MARKER_BEFORE_SLEEP" Enter 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
& $PSMUX send-keys -t $S25 "Start-Sleep -Seconds 30" Enter 2>&1 | Out-Null
Start-Sleep -Seconds 1
# Send Ctrl+C to interrupt
& $PSMUX send-keys -t $S25 C-c 2>&1 | Out-Null
Start-Sleep -Seconds 1
# Check if we got our prompt back
$capture = & $PSMUX capture-pane -t $S25 -p 2>&1
$captureText = ($capture -join "`n")
if ($captureText -match "MARKER_BEFORE_SLEEP" -or $captureText -match "PS ") {
Write-Pass "#25e: Ctrl+C forwarded (prompt visible after interrupt)"
} else {
Write-Fail "#25e: Ctrl+C may not have been forwarded. Capture: $($captureText.Substring(0, [Math]::Min(200, $captureText.Length)))"
}
# --- 25f: select-window with base-index 0 ---
Write-Test "#25f: select-window with base-index 0"
& $PSMUX set-option -t $S25 base-index 0 2>&1 | Out-Null
Start-Sleep -Milliseconds 300
& $PSMUX select-window -t "${S25}:0" 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$idx = & $PSMUX display-message -t $S25 -p '#{window_index}' 2>&1
if ("$idx".Trim() -match "0") {
Write-Pass "#25f: select-window 0 works with base-index 0"
} else {
Write-Fail "#25f: Expected window 0, got: $idx"
}
& $PSMUX set-option -t $S25 base-index 1 2>&1 | Out-Null
Start-Sleep -Milliseconds 300
# Cleanup
& $PSMUX kill-session -t $S25 2>&1 | Out-Null
Start-Sleep -Seconds 1
}
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ ISSUE #25 (Part 2): Custom prefix + digit window switching ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section "25b" "Custom prefix key + digit window switch"
$S25b = "issue25b_test_$(Get-Random)"
Start-Process -FilePath $PSMUX -ArgumentList "new-session", "-d", "-s", $S25b -WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
$ls25b = (& $PSMUX ls 2>&1) -join "`n"
if ($ls25b -notmatch [regex]::Escape($S25b)) {
Write-Fail "#25b-custom: Could not start session"
} else {
# Set custom prefix
& $PSMUX set-option -t $S25b prefix C-a 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
Write-Test "#25b-custom: Verify custom prefix was set"
$opts = & $PSMUX show-options -t $S25b 2>&1
$optsText = ($opts -join "`n")
if ($optsText -match "prefix.*C-a|prefix.*\u0001") {
Write-Pass "#25b-custom: Custom prefix C-a confirmed"
} else {
Write-Info "Options: $optsText"
Write-Fail "#25b-custom: Custom prefix not reflected in show-options"
}
# Create windows and test switching
& $PSMUX new-window -t $S25b 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
& $PSMUX new-window -t $S25b 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
Write-Test "#25b-custom: Window switching via select-window still works"
& $PSMUX select-window -t "${S25b}:1" 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$idx = & $PSMUX display-message -t $S25b -p '#{window_index}' 2>&1
if ("$idx".Trim() -match "1") {
Write-Pass "#25b-custom: select-window works with custom prefix"
} else {
Write-Fail "#25b-custom: Expected window 1, got: $idx"
}
# Cleanup
& $PSMUX kill-session -t $S25b 2>&1 | Out-Null
Start-Sleep -Seconds 1
}
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ ISSUE #19 (Deep): Verify bind-key actually works end-to-end ║
# ║ Create config with bind, start session, verify via list-keys, ║
# ║ then test the bound action produces the expected result ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section "19-deep" "bind-key end-to-end verification"
$S19d = "issue19deep_$(Get-Random)"
Write-Test "#19-deep-a: Start session and add binding at runtime"
Start-Process -FilePath $PSMUX -ArgumentList "new-session", "-d", "-s", $S19d -WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
# Try adding a binding at runtime via the CLI
$bindResult = & $PSMUX bind-key -t $S19d r "split-window -h" 2>&1
Write-Info "Runtime bind-key result: $bindResult"
$keys19d = & $PSMUX list-keys -t $S19d 2>&1
$keys19dText = ($keys19d -join "`n")
# Check for our binding
if ($keys19dText -match "r.*split-window" -or $keys19dText -match "split.*horizontal") {
Write-Pass "#19-deep-a: Runtime bind-key 'r' -> split-window found"
} else {
Write-Fail "#19-deep-a: Runtime bind-key not found in list-keys"
Write-Info "list-keys output: $keys19dText"
}
Write-Test '#19-deep-b: Verify default bindings exist (%, ", c, n, p)'
$defaultBindings = @("%", "c", "n", "p", "d", "x")
foreach ($db in $defaultBindings) {
if ($keys19dText -match [regex]::Escape($db)) {
Write-Pass "#19-deep-b: Default binding '$db' present"
} else {
Write-Fail "#19-deep-b: Default binding '$db' missing from list-keys"
}
}
Write-Test "#19-deep-c: Count total panes before and after split command"
$panesBefore = & $PSMUX list-panes -t $S19d 2>&1
$panesBeforeCount = ($panesBefore | Measure-Object -Line).Lines
Write-Info "Panes before split: $panesBeforeCount"
& $PSMUX split-window -h -t $S19d 2>&1 | Out-Null
Start-Sleep -Seconds 1
$panesAfter = & $PSMUX list-panes -t $S19d 2>&1
$panesAfterCount = ($panesAfter | Measure-Object -Line).Lines
Write-Info "Panes after split: $panesAfterCount"
if ($panesAfterCount -gt $panesBeforeCount) {
Write-Pass "#19-deep-c: split-window -h created a new pane ($panesBeforeCount -> $panesAfterCount)"
} else {
Write-Fail "#19-deep-c: split-window did not create a new pane"
}
# Cleanup
& $PSMUX kill-session -t $S19d 2>&1 | Out-Null
Start-Sleep -Seconds 1
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ ISSUE #26: Flickering with rapid full-screen apps ║
# ║ Test: measure render output consistency with rapid updates ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section 26 "Flickering / frame tearing with rapid output"
$S26 = "issue26_test_$(Get-Random)"
Start-Process -FilePath $PSMUX -ArgumentList "new-session", "-d", "-s", $S26 -WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
$ls26 = (& $PSMUX ls 2>&1) -join "`n"
if ($ls26 -notmatch [regex]::Escape($S26)) {
Write-Fail "#26: Could not start session"
} else {
Write-Test "#26a: Rapid output doesn't crash psmux"
# Send a rapid output command (simulate htop-like behavior)
& $PSMUX send-keys -t $S26 'for ($i=0; $i -lt 50; $i++) { Write-Host ("X" * 80); Start-Sleep -Milliseconds 10 }' Enter 2>&1 | Out-Null
Start-Sleep -Seconds 3
# Verify session is still alive
$ls26b = (& $PSMUX ls 2>&1) -join "`n"
if ($ls26b -match [regex]::Escape($S26)) {
Write-Pass "#26a: Session survives rapid output"
} else {
Write-Fail "#26a: Session died during rapid output!"
}
Write-Test "#26b: capture-pane works after rapid output"
$cap = & $PSMUX capture-pane -t $S26 -p 2>&1
if ($cap) {
Write-Pass "#26b: capture-pane returned content after rapid output"
} else {
Write-Fail "#26b: capture-pane returned empty after rapid output"
}
# Cleanup
& $PSMUX kill-session -t $S26 2>&1 | Out-Null
Start-Sleep -Seconds 1
}
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ EXTRA: Config file loading from multiple paths ║
# ║ Verifies ~/.psmux.conf, ~/.psmuxrc, ~/.tmux.conf loading order ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section "19-paths" "Config file loading from multiple paths"
Write-Test "#19-paths: Verify config search paths exist in code"
# This is a code-level check — the config should try these paths
$configPaths = @(
"$env:USERPROFILE\.psmux.conf",
"$env:USERPROFILE\.psmuxrc",
"$env:USERPROFILE\.tmux.conf",
"$env:USERPROFILE\.config\psmux\psmux.conf"
)
foreach ($cp in $configPaths) {
if (Test-Path $cp) {
Write-Info "Config file exists: $cp"
} else {
Write-Info "Config file NOT present: $cp (will be skipped)"
}
}
Write-Pass "#19-paths: Config path check completed"
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ EXTRA: Multi-window operations stress test ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section "stress" "Multi-window operations stress test"
$SSTRESS = "stress_test_$(Get-Random)"
Start-Process -FilePath $PSMUX -ArgumentList "new-session", "-d", "-s", $SSTRESS -WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
Write-Test "Stress: Create 5 windows rapidly"
for ($i = 0; $i -lt 5; $i++) {
& $PSMUX new-window -t $SSTRESS 2>&1 | Out-Null
Start-Sleep -Milliseconds 200
}
Start-Sleep -Seconds 1
$wcount = & $PSMUX list-windows -t $SSTRESS 2>&1
$wlines = ($wcount | Measure-Object -Line).Lines
Write-Info "Windows created: $wlines"
if ($wlines -ge 5) {
Write-Pass "Stress: Created 5+ windows"
} else {
Write-Fail "Stress: Expected at least 5 windows, got $wlines"
}
Write-Test "Stress: Rapid window switching"
for ($i = 1; $i -le 5; $i++) {
& $PSMUX select-window -t "${SSTRESS}:$i" 2>&1 | Out-Null
Start-Sleep -Milliseconds 100
}
Start-Sleep -Milliseconds 500
$lsStress = (& $PSMUX ls 2>&1) -join "`n"
if ($lsStress -match [regex]::Escape($SSTRESS)) {
Write-Pass "Stress: Session alive after rapid switching"
} else {
Write-Fail "Stress: Session died during rapid switching!"
}
Write-Test "Stress: Split pane in active window"
& $PSMUX split-window -h -t $SSTRESS 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
& $PSMUX split-window -v -t $SSTRESS 2>&1 | Out-Null
Start-Sleep -Milliseconds 500
$panes = & $PSMUX list-panes -t $SSTRESS 2>&1
$paneCount = ($panes | Measure-Object -Line).Lines
Write-Info "Panes in active window: $paneCount"
if ($paneCount -ge 3) {
Write-Pass "Stress: Multiple splits successful"
} else {
Write-Fail "Stress: Expected 3+ panes, got $paneCount"
}
# Cleanup
& $PSMUX kill-session -t $SSTRESS 2>&1 | Out-Null
Start-Sleep -Seconds 1
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ EXTRA: send-keys special characters (Issues #15, #17, #18) ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Section "keys" "Special key handling (backslash, space, backspace)"
$SKEYS = "keys_test_$(Get-Random)"
Start-Process -FilePath $PSMUX -ArgumentList "new-session", "-d", "-s", $SKEYS -WindowStyle Hidden | Out-Null
Start-Sleep -Seconds 3
$lsKeys = (& $PSMUX ls 2>&1) -join "`n"
if ($lsKeys -notmatch [regex]::Escape($SKEYS)) {
Write-Fail "Keys: Could not start session"
} else {
Write-Test "Keys: send-keys Space (#17)"
& $PSMUX send-keys -t $SKEYS "echo" Space "HELLO" Enter 2>&1 | Out-Null
Start-Sleep -Seconds 1
$cap = & $PSMUX capture-pane -t $SKEYS -p 2>&1
$capText = ($cap -join "`n")
if ($capText -match "HELLO") {
Write-Pass "Keys: Space key sent correctly (echo HELLO)"
} else {
Write-Fail "Keys: Space not sent correctly. Capture: $($capText.Substring(0, [Math]::Min(200, $capText.Length)))"
}
Write-Test "Keys: send-keys BSpace (#18)"
# Type something, backspace, then complete — test that backspace removes single char
& $PSMUX send-keys -t $SKEYS "echo ABCX" 2>&1 | Out-Null
Start-Sleep -Milliseconds 200
& $PSMUX send-keys -t $SKEYS BSpace 2>&1 | Out-Null
Start-Sleep -Milliseconds 200
& $PSMUX send-keys -t $SKEYS "D" Enter 2>&1 | Out-Null
Start-Sleep -Seconds 1
$cap2 = & $PSMUX capture-pane -t $SKEYS -p 2>&1
$cap2Text = ($cap2 -join "`n")
if ($cap2Text -match "ABCD") {
Write-Pass "Keys: Backspace removes single character (ABCX -> ABCD)"
} else {
Write-Info "Capture after backspace: $($cap2Text.Substring(0, [Math]::Min(200, $cap2Text.Length)))"
Write-Fail "Keys: Backspace may not be working correctly"
}
Write-Test "Keys: send-keys backslash (#15)"
& $PSMUX send-keys -t $SKEYS 'echo "TEST\PATH"' Enter 2>&1 | Out-Null
Start-Sleep -Seconds 1
$cap3 = & $PSMUX capture-pane -t $SKEYS -p 2>&1
$cap3Text = ($cap3 -join "`n")
if ($cap3Text -match "TEST\\PATH|TEST.PATH") {
Write-Pass "Keys: Backslash character works"
} else {
Write-Info "Capture after backslash: $($cap3Text.Substring(0, [Math]::Min(200, $cap3Text.Length)))"
Write-Fail "Keys: Backslash may not be working correctly"
}
# Cleanup
& $PSMUX kill-session -t $SKEYS 2>&1 | Out-Null
Start-Sleep -Seconds 1
}
# ╔═══════════════════════════════════════════════════════════════════════╗
# ║ SUMMARY ║
# ╚═══════════════════════════════════════════════════════════════════════╝
Write-Host ""
Write-Host ("=" * 70) -ForegroundColor White
Write-Host " FINAL RESULTS" -ForegroundColor White
Write-Host ("=" * 70) -ForegroundColor White
Write-Host " Passed: $($script:TestsPassed)" -ForegroundColor Green
Write-Host " Failed: $($script:TestsFailed)" -ForegroundColor Red
Write-Host " Skipped: $($script:TestsSkipped)" -ForegroundColor Yellow
Write-Host ("=" * 70) -ForegroundColor White
# Final cleanup — kill any remaining test sessions
& $PSMUX kill-server 2>&1 | Out-Null
taskkill /f /im psmux.exe 2>$null | Out-Null
if ($script:TestsFailed -gt 0) {
Write-Host ""
Write-Host " *** SOME TESTS FAILED — BUGS DETECTED ***" -ForegroundColor Red
exit 1
} else {
Write-Host ""
Write-Host " All tests passed!" -ForegroundColor Green
exit 0
}