mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-07-16 00:40:39 +00:00
* Harden Pester CI and discard runspace return values * Add prioritized test backlog * Add WinUtil action logging * Add config integrity tests * Add XAML control wiring tests * Add registry and service helper tests * Add package manager tests * Add runspace behavior tests * Add tweak orchestration tests * Add install workflow tests * Add update profile tests * Add AppX removal tests * Log package installer output * Add UI state helper tests * Pin Pester test runner version * Expand Win11 Creator tests * Add preferences and theme tests * Add search filter tests * Add compile contract tests * Use single WinUtil session log * Remove installer output logging helper * Handle locked WinUtil transcript log * Avoid appending to active transcript log * Log install uninstall package identities
169 lines
6.1 KiB
PowerShell
169 lines
6.1 KiB
PowerShell
#===========================================================================
|
|
# Tests - Runspace Behavior
|
|
#===========================================================================
|
|
|
|
BeforeAll {
|
|
$script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFRunspace.ps1")
|
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFFeatureInstall.ps1")
|
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFAppxRemoval.ps1")
|
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFundoall.ps1")
|
|
|
|
function script:New-WinUtilRunspaceTestContext {
|
|
param([hashtable]$InitialSync = @{})
|
|
|
|
$script:sync = [Hashtable]::Synchronized($InitialSync)
|
|
$initialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
|
|
$syncVariable = New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList "sync", $script:sync, $null
|
|
$initialSessionState.Variables.Add($syncVariable)
|
|
$script:sync.runspace = [runspacefactory]::CreateRunspacePool(1, 2, $initialSessionState, $Host)
|
|
$script:sync.runspace.Open()
|
|
}
|
|
|
|
function script:Clear-WinUtilRunspaceTestContext {
|
|
if ($script:powershell) {
|
|
$script:powershell.Dispose()
|
|
}
|
|
|
|
if ($script:sync -and $script:sync.runspace) {
|
|
$script:sync.runspace.Close()
|
|
$script:sync.runspace.Dispose()
|
|
}
|
|
|
|
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
|
Remove-Variable -Name powershell -Scope Script -ErrorAction SilentlyContinue
|
|
Remove-Variable -Name handle -Scope Script -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
function script:Assert-WinUtilAsyncHandle {
|
|
param($Handle)
|
|
|
|
($Handle -is [System.IAsyncResult]) | Should -BeTrue
|
|
($Handle -is [array]) | Should -BeFalse
|
|
$Handle.AsyncWaitHandle.WaitOne(5000) | Should -BeTrue
|
|
}
|
|
}
|
|
|
|
Describe "Invoke-WPFRunspace behavior" {
|
|
BeforeEach {
|
|
New-WinUtilRunspaceTestContext -InitialSync @{ Marker = "shared" }
|
|
}
|
|
|
|
AfterEach {
|
|
Clear-WinUtilRunspaceTestContext
|
|
}
|
|
|
|
It "returns a single async handle with no argument list" {
|
|
$handle = Invoke-WPFRunspace -ScriptBlock {
|
|
Start-Sleep -Milliseconds 100
|
|
"no-args|$($sync.Marker)"
|
|
}
|
|
|
|
Assert-WinUtilAsyncHandle -Handle $handle
|
|
@($script:powershell.EndInvoke($handle))[0] | Should -Be "no-args|shared"
|
|
}
|
|
|
|
It "passes one named parameter" {
|
|
$handle = Invoke-WPFRunspace -ParameterList @(,("Name", "value")) -ScriptBlock {
|
|
param([string]$Name)
|
|
|
|
Start-Sleep -Milliseconds 100
|
|
"Name=$Name"
|
|
}
|
|
|
|
Assert-WinUtilAsyncHandle -Handle $handle
|
|
@($script:powershell.EndInvoke($handle))[0] | Should -Be "Name=value"
|
|
}
|
|
|
|
It "passes multiple named parameters" {
|
|
$handle = Invoke-WPFRunspace -ParameterList @(
|
|
("First", "alpha"),
|
|
("Second", "beta")
|
|
) -ScriptBlock {
|
|
param(
|
|
[string]$First,
|
|
[string]$Second
|
|
)
|
|
|
|
Start-Sleep -Milliseconds 100
|
|
"$First|$Second|$($sync.Marker)"
|
|
}
|
|
|
|
Assert-WinUtilAsyncHandle -Handle $handle
|
|
@($script:powershell.EndInvoke($handle))[0] | Should -Be "alpha|beta|shared"
|
|
}
|
|
|
|
It "surfaces scriptblock failures through the owning PowerShell instance" {
|
|
$handle = Invoke-WPFRunspace -ScriptBlock {
|
|
Start-Sleep -Milliseconds 100
|
|
throw "runspace failure"
|
|
}
|
|
|
|
Assert-WinUtilAsyncHandle -Handle $handle
|
|
{ $script:powershell.EndInvoke($handle) } | Should -Throw -ExpectedMessage "*runspace failure*"
|
|
}
|
|
}
|
|
|
|
Describe "Public runspace callers" {
|
|
BeforeEach {
|
|
$script:sync = [Hashtable]::Synchronized(@{
|
|
ProcessRunning = $false
|
|
selectedFeatures = [System.Collections.Generic.List[string]]::new()
|
|
selectedTweaks = [System.Collections.Generic.List[string]]::new()
|
|
selectedAppx = [System.Collections.Generic.List[string]]::new()
|
|
configs = @{
|
|
appxHashtable = @{}
|
|
}
|
|
})
|
|
|
|
Mock Invoke-WPFRunspace { [pscustomobject]@{ MockHandle = $true } }
|
|
}
|
|
|
|
AfterEach {
|
|
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
It "queues selected feature installation without executing the runspace body" {
|
|
$script:sync.selectedFeatures.Add("WPFFeaturesSandbox")
|
|
|
|
Invoke-WPFFeatureInstall
|
|
|
|
Should -Invoke -CommandName Invoke-WPFRunspace -Times 1 -Exactly -ParameterFilter {
|
|
$ScriptBlock -is [scriptblock] -and $null -eq $ArgumentList -and $null -eq $ParameterList
|
|
}
|
|
}
|
|
|
|
It "passes selected tweaks as the runspace argument list for undo all" {
|
|
$script:sync.selectedTweaks.Add("WPFTweaksTelemetry")
|
|
$script:sync.selectedTweaks.Add("WPFTweaksServices")
|
|
|
|
Invoke-WPFundoall
|
|
|
|
Should -Invoke -CommandName Invoke-WPFRunspace -Times 1 -Exactly -ParameterFilter {
|
|
$ScriptBlock -is [scriptblock] -and
|
|
$ArgumentList.Count -eq 2 -and
|
|
$ArgumentList[0] -eq "WPFTweaksTelemetry" -and
|
|
$ArgumentList[1] -eq "WPFTweaksServices"
|
|
}
|
|
}
|
|
|
|
It "passes selected AppX items and app metadata to the removal runspace" {
|
|
$script:sync.selectedAppx.Add("WPFAppxExample")
|
|
$script:sync.configs.appxHashtable["WPFAppxExample"] = [pscustomobject]@{
|
|
Content = "Example"
|
|
PackageId = "Example.Package"
|
|
}
|
|
|
|
Invoke-WPFAppxRemoval
|
|
|
|
Should -Invoke -CommandName Invoke-WPFRunspace -Times 1 -Exactly -ParameterFilter {
|
|
$ScriptBlock -is [scriptblock] -and
|
|
$ParameterList.Count -eq 2 -and
|
|
$ParameterList[0][0] -eq "selected" -and
|
|
$ParameterList[0][1][0] -eq "WPFAppxExample" -and
|
|
$ParameterList[1][0] -eq "apps" -and
|
|
$ParameterList[1][1].ContainsKey("WPFAppxExample")
|
|
}
|
|
}
|
|
}
|