psmux 3.3.4

Terminal multiplexer for Windows - tmux alternative for PowerShell and Windows Terminal
#!/usr/bin/env pwsh
# Test: split-window -t does not reliably focus the newly created pane
# Issue: https://github.com/psmux/psmux/issues/112
#
# tmux parity: split-window should move focus to the newly created pane
# regardless of whether -t is used to specify a target.

$ErrorActionPreference = "Continue"
$pass = 0
$fail = 0
$total = 0

function Test-Check {
    param([string]$Name, [string]$Expected, [string]$Actual)
    $script:total++
    $trimExpected = $Expected.Trim()
    $trimActual = $Actual.Trim()
    if ($trimExpected -eq $trimActual) {
        $script:pass++
        Write-Host "  PASS: $Name (got '$trimActual')" -ForegroundColor Green
    } else {
        $script:fail++
        Write-Host "  FAIL: $Name - expected '$trimExpected', got '$trimActual'" -ForegroundColor Red
    }
}

# Clean up any leftover sessions
Write-Host "`n=== Cleaning up old sessions ===" -ForegroundColor Cyan
psmux kill-server 2>$null
Start-Sleep -Milliseconds 500

# ─────────────────────────────────────────────────────────────────────────────
# TEST 1: Basic reproduction from issue #112
# ─────────────────────────────────────────────────────────────────────────────
Write-Host "`n=== TEST 1: Issue #112 exact reproduction ===" -ForegroundColor Cyan

psmux new-session -d -s test112 -x 200 -y 50
Start-Sleep -Milliseconds 1500

# Verify initial state: 1 pane, pane_index = 0
$result = psmux display-message -t test112 -p '#{pane_index}'
Test-Check "Initial active pane is 0" "0" $result

$paneCount = psmux display-message -t test112 -p '#{window_panes}'
Test-Check "Initial pane count is 1" "1" $paneCount

# First targeted split
psmux split-window -h -t test112
Start-Sleep -Milliseconds 1500

$paneCount = psmux display-message -t test112 -p '#{window_panes}'
Test-Check "After first split, pane count is 2" "2" $paneCount

$result = psmux display-message -t test112 -p '#{pane_index}'
Test-Check "After split-window -h -t, focus on pane 1 (new pane)" "1" $result

# Second targeted split
psmux split-window -v -t test112
Start-Sleep -Milliseconds 1500

$paneCount = psmux display-message -t test112 -p '#{window_panes}'
Test-Check "After second split, pane count is 3" "3" $paneCount

$result = psmux display-message -t test112 -p '#{pane_index}'
Test-Check "After split-window -v -t, focus on pane 2 (new pane)" "2" $result

psmux kill-session -t test112 2>$null
Start-Sleep -Milliseconds 500

# ─────────────────────────────────────────────────────────────────────────────
# TEST 2: Split-window WITHOUT -t (should always work — baseline)
# ─────────────────────────────────────────────────────────────────────────────
Write-Host "`n=== TEST 2: split-window WITHOUT -t (baseline) ===" -ForegroundColor Cyan

psmux new-session -d -s baseline -x 200 -y 50
Start-Sleep -Milliseconds 1500

$result = psmux display-message -t baseline -p '#{pane_index}'
Test-Check "Baseline: initial pane 0" "0" $result

# Split without target (from inside session context)
psmux split-window -h -t baseline
Start-Sleep -Milliseconds 1500

$result = psmux display-message -t baseline -p '#{pane_index}'
Test-Check "Baseline: after horizontal split, pane 1" "1" $result

psmux split-window -v -t baseline
Start-Sleep -Milliseconds 1500

$result = psmux display-message -t baseline -p '#{pane_index}'
Test-Check "Baseline: after vertical split, pane 2" "2" $result

psmux kill-session -t baseline 2>$null
Start-Sleep -Milliseconds 500

# ─────────────────────────────────────────────────────────────────────────────
# TEST 3: Repeated targeted splits (stress test for race condition)
# ─────────────────────────────────────────────────────────────────────────────
Write-Host "`n=== TEST 3: Repeated targeted splits (race condition stress) ===" -ForegroundColor Cyan

psmux new-session -d -s stress -x 200 -y 50
Start-Sleep -Milliseconds 1500

for ($i = 1; $i -le 5; $i++) {
    # Alternate h/v splits to avoid running out of space in one dimension
    if ($i % 2 -eq 1) { $dir = "-h" } else { $dir = "-v" }
    psmux split-window $dir -t stress
    Start-Sleep -Milliseconds 1000
    $result = psmux display-message -t stress -p '#{pane_index}'
    Test-Check "Stress split ${i}: focus on pane ${i}" "$i" $result
}

psmux kill-session -t stress 2>$null
Start-Sleep -Milliseconds 500

# ─────────────────────────────────────────────────────────────────────────────
# TEST 4: Split targeting specific pane by index (non-active pane)
# ─────────────────────────────────────────────────────────────────────────────
Write-Host "`n=== TEST 4: Split targeting specific pane ===" -ForegroundColor Cyan

psmux new-session -d -s targetpane -x 200 -y 50
Start-Sleep -Milliseconds 1500

# Create initial split: pane 0 and pane 1, focus on pane 1
psmux split-window -h -t targetpane
Start-Sleep -Milliseconds 1500

$result = psmux display-message -t targetpane -p '#{pane_index}'
Test-Check "Target pane: after first split, active is 1" "1" $result

# Now split pane 0 specifically (non-active pane) using :0.0 target
psmux split-window -v -t targetpane:0.0
Start-Sleep -Milliseconds 1500

$paneCount = psmux display-message -t targetpane -p '#{window_panes}'
Test-Check "Target pane: after targeting pane 0, count is 3" "3" $paneCount

# After splitting pane 0, focus should move to the NEW pane (pane 1 in new layout)
# Tree after: Split(H, [Split(V, [Pane0, Pane2]), Pane1])
# Index order: Pane0=0, Pane2=1, Pane1=2
# The new pane (Pane2) is at index 1, so focus should be on 1
$result = psmux display-message -t targetpane -p '#{pane_index}'
Test-Check "Target pane: after split-window -v -t :0.0, focus moved to new pane (idx 1)" "1" $result

psmux kill-session -t targetpane 2>$null
Start-Sleep -Milliseconds 500

# ─────────────────────────────────────────────────────────────────────────────
# TEST 5: Rapid successive targeted splits (minimal delays)
# ─────────────────────────────────────────────────────────────────────────────
Write-Host "`n=== TEST 5: Rapid successive targeted splits ===" -ForegroundColor Cyan

psmux new-session -d -s rapid -x 200 -y 50
Start-Sleep -Milliseconds 1500

psmux split-window -h -t rapid
Start-Sleep -Milliseconds 500
psmux split-window -v -t rapid
Start-Sleep -Milliseconds 500
psmux split-window -h -t rapid
Start-Sleep -Milliseconds 500

$paneCount = psmux display-message -t rapid -p '#{window_panes}'
Test-Check "Rapid: after 3 splits, pane count is 4" "4" $paneCount

$result = psmux display-message -t rapid -p '#{pane_index}'
Test-Check "Rapid: after 3 rapid splits, focus on pane 3 (newest)" "3" $result

psmux kill-session -t rapid 2>$null
Start-Sleep -Milliseconds 500

# ─────────────────────────────────────────────────────────────────────────────
# TEST 6: Split with -d (detached) — focus should NOT move
# ─────────────────────────────────────────────────────────────────────────────
Write-Host "`n=== TEST 6: split-window -d (detached focus) ===" -ForegroundColor Cyan

psmux new-session -d -s detachtest -x 200 -y 50
Start-Sleep -Milliseconds 1500

$result = psmux display-message -t detachtest -p '#{pane_index}'
Test-Check "Detach: initial pane 0" "0" $result

psmux split-window -h -d -t detachtest
Start-Sleep -Milliseconds 1500

$paneCount = psmux display-message -t detachtest -p '#{window_panes}'
Test-Check "Detach: pane count is 2" "2" $paneCount

$result = psmux display-message -t detachtest -p '#{pane_index}'
Test-Check "Detach: after split-window -h -d, focus stays on pane 0" "0" $result

psmux kill-session -t detachtest 2>$null
Start-Sleep -Milliseconds 500

# ─────────────────────────────────────────────────────────────────────────────
# SUMMARY
# ─────────────────────────────────────────────────────────────────────────────
Write-Host "`n=============================" -ForegroundColor Cyan
Write-Host "RESULTS: $pass passed, $fail failed out of $total tests" -ForegroundColor $(if ($fail -eq 0) { "Green" } else { "Red" })
Write-Host "=============================" -ForegroundColor Cyan

# Clean up
psmux kill-server 2>$null

exit $fail