Files
hrynco-kswitcher/tests/screenshot_process.ps1

74 lines
4.5 KiB
PowerShell

param([string]$Executable = "$PSScriptRoot\..\build\staged\KSwitcher.Screenshot.exe")
$ErrorActionPreference='Stop'
if (Get-Process KSwitcher.Screenshot -ErrorAction SilentlyContinue) { throw 'Close existing screenshot editors before this test.' }
Add-Type @'
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
public static class ScreenshotProcessTest {
public delegate bool EnumProc(IntPtr w, IntPtr p);
[DllImport("user32.dll")] static extern bool EnumWindows(EnumProc callback, IntPtr param);
[DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr w, out uint pid);
[DllImport("user32.dll", CharSet=CharSet.Unicode)] static extern int GetClassName(IntPtr w, StringBuilder name, int count);
[DllImport("user32.dll", CharSet=CharSet.Unicode)] static extern int GetWindowText(IntPtr w, StringBuilder name, int count);
[DllImport("user32.dll")] public static extern bool PostMessage(IntPtr w, uint msg, IntPtr wp, IntPtr lp);
public static IntPtr[] Windows(int process, string cls) {
var windows=new List<IntPtr>();
EnumWindows((w,p)=>{ uint pid; GetWindowThreadProcessId(w,out pid);
var name=new StringBuilder(256); GetClassName(w,name,256);
if(pid==process && name.ToString()==cls) windows.Add(w); return true;
},IntPtr.Zero); return windows.ToArray();
}
public static string Title(IntPtr w) { var s=new StringBuilder(256); GetWindowText(w,s,256); return s.ToString(); }
}
'@
function Wait-For([scriptblock]$Check,[string]$Message) {
for($attempt=0;$attempt -lt 100;$attempt++) { if (& $Check) { return }; Start-Sleep -Milliseconds 50 }
throw $Message
}
function Send($Window,$Message,$Wparam=0,$Lparam=0) {
[ScreenshotProcessTest]::PostMessage($Window,$Message,[IntPtr]$Wparam,[IntPtr]$Lparam) | Out-Null
}
function Capture-Windows { @([ScreenshotProcessTest]::Windows($script:process.Id,'KSwitcher.Capture')) }
function Select-Region($Window) {
Send $Window 0x201 1 ((40 -shl 16) -bor 40)
Send $Window 0x200 1 ((240 -shl 16) -bor 360)
Send $Window 0x202 0 ((240 -shl 16) -bor 360)
Wait-For { (Capture-Windows) -notcontains $Window } 'Selection did not close after copying (notifications may be disabled).'
}
function Close-Editor($Window) {
Send $Window 0x10
Wait-For { (Capture-Windows) -notcontains $Window } 'Unedited copied screenshot did not close.'
}
function Latest-Token {
(Get-ChildItem -LiteralPath (Join-Path $env:LOCALAPPDATA 'KSwitcher/ScreenshotNotifications') -Filter '*.capture' | Sort-Object LastWriteTimeUtc -Descending | Select-Object -First 1).BaseName
}
$process=$null
try {
$process=Start-Process -FilePath $Executable -ArgumentList @("--auto-open-editor=0") -WindowStyle Hidden -PassThru
Wait-For { (Capture-Windows).Count -eq 1 } 'First selection did not open.'
Select-Region (Capture-Windows)[0]
if (!$process.WaitForExit(5000)) { throw 'Process remained alive after notification.' }
$token=Latest-Token
$process=Start-Process -FilePath $Executable -ArgumentList @('--open',"kswitcher-screenshot:$token") -WindowStyle Hidden -PassThru
Wait-For { (Capture-Windows).Count -eq 1 } 'Notification activation did not open an editor.'
$first=(Capture-Windows)[0]
$secondLaunch=Start-Process -FilePath $Executable -ArgumentList @('--open',"kswitcher-screenshot:$token") -WindowStyle Hidden -PassThru
if (!$secondLaunch.WaitForExit(10000) -or $secondLaunch.ExitCode -ne 0) { throw 'Second activation did not hand off.' }
Wait-For { (Capture-Windows).Count -eq 2 } 'Second editor did not open in same process.'
$second=(Capture-Windows | Where-Object { $_ -ne $first })[0]
if ([ScreenshotProcessTest]::Title($first) -eq [ScreenshotProcessTest]::Title($second)) { throw 'Editor indices collide.' }
Close-Editor $first
if ($process.HasExited) { throw 'Process exited with an editor open.' }
Close-Editor $second
if (!$process.WaitForExit(5000) -or $process.ExitCode -ne 0) { throw 'Last editor did not exit process.' }
$process=Start-Process -FilePath $Executable -ArgumentList @("--auto-open-editor=0") -WindowStyle Hidden -PassThru
Wait-For { (Capture-Windows).Count -eq 1 } 'New process did not open selection.'
Send (Capture-Windows)[0] 0x100 27 # Esc cancels a selection only.
if (!$process.WaitForExit(5000) -or $process.ExitCode -ne 0) { throw 'Cancelling selection did not exit process.' }
'Passed screenshot process lifecycle checks'
} finally {
if ($process -and !$process.HasExited) { Stop-Process -Id $process.Id }
}