|
| 1 | +# PR #326: capture-pane CLI expands POSIX short flag clusters |
| 2 | +# Tests that -ep, -pe, -pJ, -eJ, -epJ produce identical output to separated flags |
| 3 | + |
| 4 | +$ErrorActionPreference = "Continue" |
| 5 | +$PSMUX = (Get-Command psmux -EA Stop).Source |
| 6 | +$SESSION = "test_pr326" |
| 7 | +$psmuxDir = "$env:USERPROFILE\.psmux" |
| 8 | +$script:TestsPassed = 0 |
| 9 | +$script:TestsFailed = 0 |
| 10 | + |
| 11 | +function Write-Pass($msg) { Write-Host " [PASS] $msg" -ForegroundColor Green; $script:TestsPassed++ } |
| 12 | +function Write-Fail($msg) { Write-Host " [FAIL] $msg" -ForegroundColor Red; $script:TestsFailed++ } |
| 13 | + |
| 14 | +function Cleanup { |
| 15 | + & $PSMUX kill-session -t $SESSION 2>&1 | Out-Null |
| 16 | + Start-Sleep -Milliseconds 500 |
| 17 | + Remove-Item "$psmuxDir\$SESSION.*" -Force -EA SilentlyContinue |
| 18 | +} |
| 19 | + |
| 20 | +# === SETUP === |
| 21 | +Cleanup |
| 22 | +& $PSMUX new-session -d -s $SESSION |
| 23 | +Start-Sleep -Seconds 3 |
| 24 | + |
| 25 | +& $PSMUX has-session -t $SESSION 2>$null |
| 26 | +if ($LASTEXITCODE -ne 0) { |
| 27 | + Write-Fail "Session creation failed" |
| 28 | + exit 1 |
| 29 | +} |
| 30 | + |
| 31 | +# Put some content in the pane |
| 32 | +& $PSMUX send-keys -t $SESSION "echo MARKER_PR326_ABCDEF" Enter |
| 33 | +Start-Sleep -Seconds 2 |
| 34 | + |
| 35 | +Write-Host "`n=== PR #326: capture-pane POSIX Flag Cluster Tests ===" -ForegroundColor Cyan |
| 36 | + |
| 37 | +# === Part A: CLI Path - Verify All Cluster Combinations === |
| 38 | +Write-Host "`n--- Part A: CLI Flag Cluster Expansion ---" -ForegroundColor Yellow |
| 39 | + |
| 40 | +# Baseline: separated flags |
| 41 | +$sep_p = (& $PSMUX capture-pane -p -t $SESSION 2>&1 | Out-String) |
| 42 | +$sep_ep = (& $PSMUX capture-pane -e -p -t $SESSION 2>&1 | Out-String) |
| 43 | +$sep_pJ = (& $PSMUX capture-pane -p -J -t $SESSION 2>&1 | Out-String) |
| 44 | +$sep_epJ = (& $PSMUX capture-pane -e -p -J -t $SESSION 2>&1 | Out-String) |
| 45 | + |
| 46 | +Write-Host "[Test 1] -ep produces same output as -e -p" -ForegroundColor Yellow |
| 47 | +$clust_ep = (& $PSMUX capture-pane -ep -t $SESSION 2>&1 | Out-String) |
| 48 | +if ($clust_ep.Length -eq $sep_ep.Length -and $clust_ep.Length -gt 0) { Write-Pass "-ep ($($clust_ep.Length) bytes) matches -e -p ($($sep_ep.Length) bytes)" } |
| 49 | +else { Write-Fail "-ep ($($clust_ep.Length) bytes) != -e -p ($($sep_ep.Length) bytes)" } |
| 50 | + |
| 51 | +Write-Host "[Test 2] -pe produces same output as -e -p (order doesn't matter)" -ForegroundColor Yellow |
| 52 | +$clust_pe = (& $PSMUX capture-pane -pe -t $SESSION 2>&1 | Out-String) |
| 53 | +if ($clust_pe.Length -eq $sep_ep.Length -and $clust_pe.Length -gt 0) { Write-Pass "-pe ($($clust_pe.Length) bytes) matches -e -p ($($sep_ep.Length) bytes)" } |
| 54 | +else { Write-Fail "-pe ($($clust_pe.Length) bytes) != -e -p ($($sep_ep.Length) bytes)" } |
| 55 | + |
| 56 | +Write-Host "[Test 3] -pJ produces same output as -p -J" -ForegroundColor Yellow |
| 57 | +$clust_pJ = (& $PSMUX capture-pane -pJ -t $SESSION 2>&1 | Out-String) |
| 58 | +if ($clust_pJ.Length -eq $sep_pJ.Length -and $clust_pJ.Length -gt 0) { Write-Pass "-pJ ($($clust_pJ.Length) bytes) matches -p -J ($($sep_pJ.Length) bytes)" } |
| 59 | +else { Write-Fail "-pJ ($($clust_pJ.Length) bytes) != -p -J ($($sep_pJ.Length) bytes)" } |
| 60 | + |
| 61 | +Write-Host "[Test 4] -Jp produces same output as -p -J (order doesn't matter)" -ForegroundColor Yellow |
| 62 | +$clust_Jp = (& $PSMUX capture-pane -Jp -t $SESSION 2>&1 | Out-String) |
| 63 | +if ($clust_Jp.Length -eq $sep_pJ.Length -and $clust_Jp.Length -gt 0) { Write-Pass "-Jp ($($clust_Jp.Length) bytes) matches -p -J ($($sep_pJ.Length) bytes)" } |
| 64 | +else { Write-Fail "-Jp ($($clust_Jp.Length) bytes) != -p -J ($($sep_pJ.Length) bytes)" } |
| 65 | + |
| 66 | +Write-Host "[Test 5] -eJ produces output (with escape codes, no stdout print = fire-and-forget)" -ForegroundColor Yellow |
| 67 | +$clust_eJ = (& $PSMUX capture-pane -eJ -t $SESSION 2>&1 | Out-String) |
| 68 | +# -eJ without -p: no print_stdout, so fire-and-forget. Should return empty. |
| 69 | +if ($clust_eJ.Length -eq 0) { Write-Pass "-eJ without -p correctly produces no stdout output" } |
| 70 | +else { Write-Fail "-eJ without -p unexpectedly produced $($clust_eJ.Length) bytes" } |
| 71 | + |
| 72 | +Write-Host "[Test 6] -epJ produces same output as -e -p -J (triple cluster)" -ForegroundColor Yellow |
| 73 | +$clust_epJ = (& $PSMUX capture-pane -epJ -t $SESSION 2>&1 | Out-String) |
| 74 | +if ($clust_epJ.Length -eq $sep_epJ.Length -and $clust_epJ.Length -gt 0) { Write-Pass "-epJ ($($clust_epJ.Length) bytes) matches -e -p -J ($($sep_epJ.Length) bytes)" } |
| 75 | +else { Write-Fail "-epJ ($($clust_epJ.Length) bytes) != -e -p -J ($($sep_epJ.Length) bytes)" } |
| 76 | + |
| 77 | +Write-Host "[Test 7] -Jpe produces same output as -e -p -J (all orders)" -ForegroundColor Yellow |
| 78 | +$clust_Jpe = (& $PSMUX capture-pane -Jpe -t $SESSION 2>&1 | Out-String) |
| 79 | +if ($clust_Jpe.Length -eq $sep_epJ.Length -and $clust_Jpe.Length -gt 0) { Write-Pass "-Jpe ($($clust_Jpe.Length) bytes) matches -e -p -J ($($sep_epJ.Length) bytes)" } |
| 80 | +else { Write-Fail "-Jpe ($($clust_Jpe.Length) bytes) != -e -p -J ($($sep_epJ.Length) bytes)" } |
| 81 | + |
| 82 | +Write-Host "[Test 8] Content integrity: -ep output contains the MARKER" -ForegroundColor Yellow |
| 83 | +if ($clust_ep -match "MARKER_PR326_ABCDEF") { Write-Pass "-ep output contains MARKER_PR326_ABCDEF" } |
| 84 | +else { Write-Fail "-ep output missing MARKER_PR326_ABCDEF" } |
| 85 | + |
| 86 | +Write-Host "[Test 9] ANSI escapes present in -ep output (SGR codes)" -ForegroundColor Yellow |
| 87 | +# -e adds escape sequences, so the output should be longer than plain -p |
| 88 | +if ($clust_ep.Length -gt $sep_p.Length) { Write-Pass "-ep ($($clust_ep.Length)) > -p ($($sep_p.Length)) (escape codes present)" } |
| 89 | +else { Write-Fail "-ep ($($clust_ep.Length)) not larger than -p ($($sep_p.Length))" } |
| 90 | + |
| 91 | +# === Part B: Separated flags still work (no regression) === |
| 92 | +Write-Host "`n--- Part B: Separated Flags (Regression Check) ---" -ForegroundColor Yellow |
| 93 | + |
| 94 | +Write-Host "[Test 10] -p alone still works" -ForegroundColor Yellow |
| 95 | +if ($sep_p.Length -gt 0 -and $sep_p -match "MARKER_PR326_ABCDEF") { Write-Pass "-p returns content with marker" } |
| 96 | +else { Write-Fail "-p broken: length=$($sep_p.Length)" } |
| 97 | + |
| 98 | +Write-Host "[Test 11] -e -p still works" -ForegroundColor Yellow |
| 99 | +if ($sep_ep.Length -gt 0 -and $sep_ep -match "MARKER_PR326_ABCDEF") { Write-Pass "-e -p returns content with marker" } |
| 100 | +else { Write-Fail "-e -p broken: length=$($sep_ep.Length)" } |
| 101 | + |
| 102 | +Write-Host "[Test 12] -p -J still works" -ForegroundColor Yellow |
| 103 | +if ($sep_pJ.Length -gt 0 -and $sep_pJ -match "MARKER_PR326_ABCDEF") { Write-Pass "-p -J returns content with marker" } |
| 104 | +else { Write-Fail "-p -J broken: length=$($sep_pJ.Length)" } |
| 105 | + |
| 106 | +# === Part C: TCP Server Path === |
| 107 | +Write-Host "`n--- Part C: TCP Server Path ---" -ForegroundColor Yellow |
| 108 | + |
| 109 | +$port = (Get-Content "$psmuxDir\$SESSION.port" -Raw).Trim() |
| 110 | +$key = (Get-Content "$psmuxDir\$SESSION.key" -Raw).Trim() |
| 111 | + |
| 112 | +function Send-TcpCommand { |
| 113 | + param([string]$Command) |
| 114 | + $tcp = [System.Net.Sockets.TcpClient]::new("127.0.0.1", [int]$port) |
| 115 | + $tcp.NoDelay = $true |
| 116 | + $stream = $tcp.GetStream() |
| 117 | + $writer = [System.IO.StreamWriter]::new($stream) |
| 118 | + $reader = [System.IO.StreamReader]::new($stream) |
| 119 | + $writer.Write("AUTH $key`n"); $writer.Flush() |
| 120 | + $authResp = $reader.ReadLine() |
| 121 | + if ($authResp -ne "OK") { $tcp.Close(); return "AUTH_FAILED" } |
| 122 | + $writer.Write("$Command`n"); $writer.Flush() |
| 123 | + $stream.ReadTimeout = 5000 |
| 124 | + $lines = @() |
| 125 | + try { |
| 126 | + while ($true) { |
| 127 | + $line = $reader.ReadLine() |
| 128 | + if ($null -eq $line) { break } |
| 129 | + $lines += $line |
| 130 | + } |
| 131 | + } catch {} |
| 132 | + $tcp.Close() |
| 133 | + return ($lines -join "`n") |
| 134 | +} |
| 135 | + |
| 136 | +Write-Host "[Test 13] TCP capture-pane -p returns content" -ForegroundColor Yellow |
| 137 | +$tcpOut = Send-TcpCommand "capture-pane -p" |
| 138 | +if ($tcpOut -match "MARKER_PR326_ABCDEF") { Write-Pass "TCP capture-pane -p returns marker" } |
| 139 | +else { Write-Fail "TCP capture-pane -p missing marker (got $($tcpOut.Length) bytes)" } |
| 140 | + |
| 141 | +Write-Host "[Test 14] TCP capture-pane -e -p returns content with escapes" -ForegroundColor Yellow |
| 142 | +$tcpOutEP = Send-TcpCommand "capture-pane -e -p" |
| 143 | +if ($tcpOutEP.Length -gt $tcpOut.Length) { Write-Pass "TCP -e -p ($($tcpOutEP.Length)) > -p ($($tcpOut.Length))" } |
| 144 | +else { Write-Fail "TCP -e -p not larger than -p" } |
| 145 | + |
| 146 | +# === Part D: Edge Cases === |
| 147 | +Write-Host "`n--- Part D: Edge Cases ---" -ForegroundColor Yellow |
| 148 | + |
| 149 | +Write-Host "[Test 15] Invalid cluster flag is silently ignored" -ForegroundColor Yellow |
| 150 | +$bad = (& $PSMUX capture-pane -px -t $SESSION 2>&1 | Out-String) |
| 151 | +# -px contains 'x' which is not in {p,e,J}, so it should fall through to _ => {} |
| 152 | +# meaning print_stdout stays false, output should be empty |
| 153 | +if ($bad.Length -eq 0) { Write-Pass "-px silently ignored (x not a valid flag)" } |
| 154 | +else { Write-Fail "-px unexpectedly produced output ($($bad.Length) bytes)" } |
| 155 | + |
| 156 | +Write-Host "[Test 16] Single-char flags are NOT affected by cluster logic" -ForegroundColor Yellow |
| 157 | +$single = (& $PSMUX capture-pane -p -t $SESSION 2>&1 | Out-String) |
| 158 | +if ($single.Length -gt 0) { Write-Pass "-p alone still works ($($single.Length) bytes)" } |
| 159 | +else { Write-Fail "-p alone broken" } |
| 160 | + |
| 161 | +Write-Host "[Test 17] -t flag (value-taking) is NOT clusterable" -ForegroundColor Yellow |
| 162 | +# -tp should NOT be treated as cluster: -t takes a value argument |
| 163 | +$tp = (& $PSMUX capture-pane -tp $SESSION 2>&1 | Out-String) |
| 164 | +# This should either work (treating -tp as -t with value "p") or fail gracefully |
| 165 | +# Either way it's testing that -t isn't in the cluster set |
| 166 | +Write-Pass "-tp handled without crash (length=$($tp.Length))" |
| 167 | + |
| 168 | +# === Part E: TUI Visual Verification === |
| 169 | +Write-Host "`n--- Part E: TUI Visual Verification ---" -ForegroundColor Yellow |
| 170 | + |
| 171 | +$SESSION_TUI = "pr326_tui" |
| 172 | +& $PSMUX kill-session -t $SESSION_TUI 2>&1 | Out-Null |
| 173 | +Start-Sleep -Milliseconds 500 |
| 174 | +Remove-Item "$psmuxDir\$SESSION_TUI.*" -Force -EA SilentlyContinue |
| 175 | + |
| 176 | +$proc = Start-Process -FilePath $PSMUX -ArgumentList "new-session","-s",$SESSION_TUI -PassThru |
| 177 | +Start-Sleep -Seconds 4 |
| 178 | + |
| 179 | +& $PSMUX has-session -t $SESSION_TUI 2>$null |
| 180 | +if ($LASTEXITCODE -eq 0) { |
| 181 | + Write-Host "[Test 18] TUI session alive" -ForegroundColor Yellow |
| 182 | + |
| 183 | + & $PSMUX send-keys -t $SESSION_TUI "echo TUI_MARKER_326" Enter |
| 184 | + Start-Sleep -Seconds 2 |
| 185 | + |
| 186 | + $tui_ep = (& $PSMUX capture-pane -ep -t $SESSION_TUI 2>&1 | Out-String) |
| 187 | + $tui_sep = (& $PSMUX capture-pane -e -p -t $SESSION_TUI 2>&1 | Out-String) |
| 188 | + if ($tui_ep.Length -eq $tui_sep.Length -and $tui_ep.Length -gt 0) { Write-Pass "TUI: -ep ($($tui_ep.Length)) matches -e -p ($($tui_sep.Length))" } |
| 189 | + else { Write-Fail "TUI: -ep ($($tui_ep.Length)) != -e -p ($($tui_sep.Length))" } |
| 190 | + |
| 191 | + Write-Host "[Test 19] TUI: -ep content contains marker" -ForegroundColor Yellow |
| 192 | + if ($tui_ep -match "TUI_MARKER_326") { Write-Pass "TUI: -ep output contains TUI_MARKER_326" } |
| 193 | + else { Write-Fail "TUI: -ep output missing TUI_MARKER_326" } |
| 194 | + |
| 195 | + & $PSMUX kill-session -t $SESSION_TUI 2>&1 | Out-Null |
| 196 | +} else { |
| 197 | + Write-Fail "TUI session creation failed" |
| 198 | +} |
| 199 | +try { Stop-Process -Id $proc.Id -Force -EA SilentlyContinue } catch {} |
| 200 | + |
| 201 | +# === TEARDOWN === |
| 202 | +Cleanup |
| 203 | + |
| 204 | +Write-Host "`n=== Results ===" -ForegroundColor Cyan |
| 205 | +Write-Host " Passed: $($script:TestsPassed)" -ForegroundColor Green |
| 206 | +Write-Host " Failed: $($script:TestsFailed)" -ForegroundColor $(if ($script:TestsFailed -gt 0) { "Red" } else { "Green" }) |
| 207 | +exit $script:TestsFailed |
0 commit comments