fix: preserve selections when config import is invalid (#4994)

* fix: validate imports before replacing selections

* test: cover atomic config imports

* docs: explain stale config imports

---------

Co-authored-by: Guilherme de Oliveira Rocha <contatoguilhermeoliveira@protonmail.com>
Co-authored-by: Chris Titus <contact@christitus.com>
This commit is contained in:
Guilherme Oliveira
2026-08-19 15:30:46 -05:00
committed by GitHub
co-authored by Guilherme de Oliveira Rocha Chris Titus
parent 2d0fd43bd3
commit 792122e998
4 changed files with 183 additions and 13 deletions
+118 -2
View File
@@ -48,12 +48,17 @@ namespace System.Windows.Controls
public class WrapPanel
{
public global::Windows.Visibility Visibility { get; set; }
public object Visibility { get; set; }
}
public class StackPanel
{
public System.Collections.ArrayList Children { get; } = new System.Collections.ArrayList();
public System.Collections.ArrayList Children { get; private set; }
public StackPanel()
{
Children = new System.Collections.ArrayList();
}
}
}
"@
@@ -61,6 +66,7 @@ namespace System.Windows.Controls
. (Join-Path $script:repoRoot "functions\private\Update-WinUtilSelections.ps1")
. (Join-Path $script:repoRoot "functions\private\Reset-WPFCheckBoxes.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFImpex.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFGetInstalled.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFSelectedCheckboxesUpdate.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFButton.ps1")
@@ -127,6 +133,16 @@ namespace System.Windows.Controls
Content = "Git"
}
}
appxHashtable = @{
WPFAppxExample = [pscustomobject]@{}
}
tweaks = [pscustomobject]@{
WPFTweaksTelemetry = [pscustomobject]@{}
WPFToggleDarkMode = [pscustomobject]@{}
}
feature = [pscustomobject]@{
WPFFeatureSandbox = [pscustomobject]@{}
}
}
WPFselectedAppsButton = [pscustomobject]@{
Content = ""
@@ -174,6 +190,106 @@ Describe "Update-WinUtilSelections" {
@($script:sync.selectedFeatures) | Should -Be @("WPFFeatureSandbox")
@($script:sync.selectedAppx) | Should -Be @("WPFAppxExample")
}
It "replaces selections only after every imported key is validated" {
$script:sync.selectedApps.Add("WPFInstallExisting")
$script:sync.selectedTweaks.Add("WPFTweaksExisting")
Update-WinUtilSelections -flatJson @(
"WPFInstallGit",
"WPFFeatureSandbox"
) -Replace
@($script:sync.selectedApps) | Should -Be @("WPFInstallGit")
@($script:sync.selectedTweaks) | Should -Be @()
@($script:sync.selectedFeatures) | Should -Be @("WPFFeatureSandbox")
}
It "preserves existing selections when an imported key is unsupported" {
$script:sync.selectedApps.Add("WPFInstallExisting")
$script:sync.selectedTweaks.Add("WPFTweaksExisting")
{
Update-WinUtilSelections -flatJson @(
"WPFInstallGit",
"NotAWinUtilKey"
) -Replace
} | Should -Throw "Unsupported selection key 'NotAWinUtilKey'."
@($script:sync.selectedApps) | Should -Be @("WPFInstallExisting")
@($script:sync.selectedTweaks) | Should -Be @("WPFTweaksExisting")
@($script:sync.selectedFeatures) | Should -Be @()
}
It "preserves existing selections when an imported key is not in the current catalog" {
$script:sync.selectedApps.Add("WPFInstallExisting")
{
Update-WinUtilSelections -flatJson @(
"WPFInstallGit",
"WPFInstallUnknown"
) -Replace
} | Should -Throw "Unknown selection key 'WPFInstallUnknown'."
@($script:sync.selectedApps) | Should -Be @("WPFInstallExisting")
@($script:sync.selectedTweaks) | Should -Be @()
@($script:sync.selectedFeatures) | Should -Be @()
}
}
Describe "Invoke-WPFImpex import selection state" {
BeforeEach {
New-WinUtilUiStateTestContext
$script:sync.Form = [pscustomobject]@{}
Mock Reset-WPFCheckBoxes { }
Mock Write-Error { }
}
AfterEach {
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
Remove-Variable -Name sync -Scope Global -ErrorAction SilentlyContinue
}
It "replaces selections and resets the UI after a valid import" {
$script:sync.selectedApps.Add("WPFInstallExisting")
$script:sync.selectedTweaks.Add("WPFTweaksExisting")
$configPath = Join-Path $TestDrive "valid-config.json"
@(
"WPFInstallGit",
"WPFFeatureSandbox"
) | ConvertTo-Json | Set-Content -LiteralPath $configPath
Invoke-WPFImpex -type "import" -Config $configPath
@($script:sync.selectedApps) | Should -Be @("WPFInstallGit")
@($script:sync.selectedTweaks) | Should -Be @()
@($script:sync.selectedFeatures) | Should -Be @("WPFFeatureSandbox")
Should -Invoke -CommandName Reset-WPFCheckBoxes -Times 1 -Exactly -ParameterFilter {
$doToggles -eq $true
}
Should -Invoke -CommandName Write-Error -Times 0 -Exactly
}
It "preserves selections and does not reset the UI after an invalid import" {
$script:sync.selectedApps.Add("WPFInstallExisting")
$script:sync.selectedTweaks.Add("WPFTweaksExisting")
$configPath = Join-Path $TestDrive "invalid-config.json"
@(
"WPFInstallGit",
"WPFInstallUnknown"
) | ConvertTo-Json | Set-Content -LiteralPath $configPath
Invoke-WPFImpex -type "import" -Config $configPath
@($script:sync.selectedApps) | Should -Be @("WPFInstallExisting")
@($script:sync.selectedTweaks) | Should -Be @("WPFTweaksExisting")
@($script:sync.selectedFeatures) | Should -Be @()
Should -Invoke -CommandName Reset-WPFCheckBoxes -Times 0 -Exactly
Should -Invoke -CommandName Write-Error -Times 1 -Exactly -ParameterFilter {
$Message -like "An error occurred while importing: *Unknown selection key 'WPFInstallUnknown'.*"
}
}
}
Describe "Invoke-WPFSelectedCheckboxesUpdate" {