Files
Win11Debloat/Tests/Replace-StartMenu.Tests.ps1

202 lines
9.5 KiB
PowerShell

BeforeAll {
function Get-UserDirectory { param($userName, $fileName, $exitIfPathNotFound) }
. (Join-Path $PSScriptRoot '..\Scripts\Features\Replace-StartMenu.ps1')
}
Describe 'Get-StartMenuUserNameFromPath' {
It 'extracts a user name from a start-menu path and falls back for unknown paths' {
Get-StartMenuUserNameFromPath -StartMenuBinFile 'C:\Users\Alice\AppData\Local\Packages\Start\start2.bin' | Should -Be 'Alice'
Get-StartMenuUserNameFromPath -StartMenuBinFile 'C:\Temp\start2.bin' | Should -Be 'unknown'
}
It 'returns the latest current-user start-menu backup' {
Mock Get-ChildItem {
@(
[PSCustomObject]@{ Name = 'Win11Debloat-StartBackup-20260101_120000.bak'; FullName = 'C:\Backups\older.bak' }
[PSCustomObject]@{ Name = 'Win11Debloat-StartBackup-20260102_120000.bak'; FullName = 'C:\Backups\newer.bak' }
)
}
Get-StartMenuBackupPath -Scope CurrentUser | Should -Be 'C:\Backups\newer.bak'
}
It 'returns the first available all-users start-menu backup' {
$script:allUsersPath = 'C:\Users\*\AppData\Local\Packages\Start\LocalState'
Mock Get-UserDirectory { $script:allUsersPath }
Mock Get-ChildItem {
param($Path)
if ($Path -eq $script:allUsersPath) {
return [PSCustomObject]@{ FullName = 'C:\Users\Alice\AppData\Local\Packages\Start\LocalState' }
}
return [PSCustomObject]@{ Name = 'Win11Debloat-StartBackup-20260103_120000.bak'; FullName = 'C:\Users\Alice\backup.bak' }
}
Get-StartMenuBackupPath -Scope AllUsers | Should -Be 'C:\Users\Alice\backup.bak'
}
It 'restores a start menu backup and preserves the replaced file' {
$script:Params = @{}
$startMenuFile = Join-Path $TestDrive 'start2.bin'
$backupFile = Join-Path $TestDrive 'Win11Debloat-StartBackup-20260101_120000.bak'
Set-Content -LiteralPath $startMenuFile -Value 'current'
Set-Content -LiteralPath $backupFile -Value 'backup'
$result = Restore-StartMenuFromBackup -StartMenuBinFile $startMenuFile -BackupFilePath $backupFile
$result.Result | Should -BeTrue
Get-Content -LiteralPath $startMenuFile -Raw | Should -Match 'backup'
@(Get-ChildItem -LiteralPath $TestDrive -Filter 'Win11Debloat-StartRestore-*.bak').Count | Should -Be 1
}
It 'reports a missing backup without changing the start-menu file' {
$script:Params = @{}
$startMenuFile = Join-Path $TestDrive 'start2.bin'
Set-Content -LiteralPath $startMenuFile -Value 'current'
$result = Restore-StartMenuFromBackup -StartMenuBinFile $startMenuFile -BackupFilePath (Join-Path $TestDrive 'missing.bak')
$result.Result | Should -BeFalse
Get-Content -LiteralPath $startMenuFile -Raw | Should -Match 'current'
}
It 'preserves a recoverable copy of the current layout when restoring fails' {
$script:Params = @{}
$startMenuFile = Join-Path $TestDrive 'start2.bin'
$backupFile = Join-Path $TestDrive 'Win11Debloat-StartBackup-20260101_120000.bak'
Set-Content -LiteralPath $startMenuFile -Value 'current'
Set-Content -LiteralPath $backupFile -Value 'backup'
Mock Copy-Item { throw 'disk full' }
$result = Restore-StartMenuFromBackup -StartMenuBinFile $startMenuFile -BackupFilePath $backupFile
$result.Result | Should -BeFalse
$result.Message | Should -Match 'disk full'
$restoreCopies = @(Get-ChildItem -LiteralPath $TestDrive -Filter 'Win11Debloat-StartRestore-*.bak')
$restoreCopies.Count | Should -Be 1
Get-Content -LiteralPath $restoreCopies[0].FullName -Raw | Should -Match 'current'
}
It 'leaves the original layout in place when it cannot be moved for restore' {
$script:Params = @{}
$startMenuFile = Join-Path $TestDrive 'start2.bin'
$backupFile = Join-Path $TestDrive 'Win11Debloat-StartBackup-20260101_120000.bak'
Set-Content -LiteralPath $startMenuFile -Value 'current'
Set-Content -LiteralPath $backupFile -Value 'backup'
Mock Move-Item { throw 'locked' }
$result = Restore-StartMenuFromBackup -StartMenuBinFile $startMenuFile -BackupFilePath $backupFile
$result.Result | Should -BeFalse
$result.Message | Should -Match 'locked'
Get-Content -LiteralPath $startMenuFile -Raw | Should -Match 'current'
}
It 'delegates current-user restore to the common backup operation' {
$script:Params = @{}
Mock Restore-StartMenuFromBackup { [PSCustomObject]@{ Result = $true } }
Restore-StartMenu -BackupFilePath 'C:\Backups\backup.bak' | Should -Not -BeNullOrEmpty
Should -Invoke Restore-StartMenuFromBackup -Times 1 -Exactly -ParameterFilter { $BackupFilePath -eq 'C:\Backups\backup.bak' }
}
It 'restores every discovered user and removes the default-profile start menu' {
$script:Params = @{}
$script:allUsersStartPath = 'C:\Users\*\LocalState'
$script:defaultStartPath = Join-Path $TestDrive 'DefaultLocalState'
$defaultBin = Join-Path $script:defaultStartPath 'start2.bin'
New-Item -ItemType Directory -Path $script:defaultStartPath | Out-Null
Set-Content -LiteralPath $defaultBin -Value 'template'
Mock Get-UserDirectory { param($userName) if ($userName -eq '*') { $script:allUsersStartPath } else { $script:defaultStartPath } }
Mock Get-ChildItem { param($Path) if ($Path -eq $script:allUsersStartPath) { [PSCustomObject]@{ FullName = 'C:\Users\Alice\LocalState' } } }
Mock Restore-StartMenuFromBackup { [PSCustomObject]@{ UserName = 'Alice'; Result = $true; Message = 'Restored' } }
$result = @(Restore-StartMenuForAllUsers -BackupFilePath 'C:\Backups\backup.bak')
$result.Count | Should -Be 2
Should -Invoke Restore-StartMenuFromBackup -Times 1 -Exactly
Test-Path -LiteralPath $defaultBin | Should -BeFalse
}
}
Describe 'Replace-StartMenu' {
BeforeEach {
$script:Params = @{}
Mock Write-Host {}
}
It 'backs up and replaces an existing start-menu file' {
$startMenuFile = Join-Path $TestDrive 'start2.bin'
$templateFile = Join-Path $TestDrive 'template.bin'
Set-Content -LiteralPath $startMenuFile -Value 'current layout'
Set-Content -LiteralPath $templateFile -Value 'replacement layout'
Replace-StartMenu -startMenuBinFile $startMenuFile -startMenuTemplate $templateFile
Get-Content -LiteralPath $startMenuFile -Raw | Should -Match 'replacement layout'
@(Get-ChildItem -LiteralPath $TestDrive -Filter 'Win11Debloat-StartBackup-*.bak').Count | Should -Be 1
}
It 'creates and replaces a missing start-menu file without a backup' {
$testDirectory = Join-Path $TestDrive 'missing-layout'
New-Item -ItemType Directory -Path $testDirectory | Out-Null
$startMenuFile = Join-Path $testDirectory 'start2.bin'
$templateFile = Join-Path $testDirectory 'template.bin'
$backupCountBefore = @(Get-ChildItem -LiteralPath $testDirectory -Filter 'Win11Debloat-StartBackup-*.bak').Count
Set-Content -LiteralPath $templateFile -Value 'replacement layout'
Replace-StartMenu -startMenuBinFile $startMenuFile -startMenuTemplate $templateFile
Get-Content -LiteralPath $startMenuFile -Raw | Should -Match 'replacement layout'
@(Get-ChildItem -LiteralPath $testDirectory -Filter 'Win11Debloat-StartBackup-*.bak').Count | Should -Be $backupCountBefore
}
It 'does not change a start-menu file in WhatIf mode' {
$script:Params = @{ WhatIf = $true }
$testDirectory = Join-Path $TestDrive 'whatif-layout'
New-Item -ItemType Directory -Path $testDirectory | Out-Null
$startMenuFile = Join-Path $testDirectory 'start2.bin'
$templateFile = Join-Path $testDirectory 'template.bin'
$backupCountBefore = @(Get-ChildItem -LiteralPath $testDirectory -Filter 'Win11Debloat-StartBackup-*.bak').Count
Set-Content -LiteralPath $startMenuFile -Value 'current layout'
Set-Content -LiteralPath $templateFile -Value 'replacement layout'
Replace-StartMenu -startMenuBinFile $startMenuFile -startMenuTemplate $templateFile
Get-Content -LiteralPath $startMenuFile -Raw | Should -Match 'current layout'
@(Get-ChildItem -LiteralPath $testDirectory -Filter 'Win11Debloat-StartBackup-*.bak').Count | Should -Be $backupCountBefore
}
}
Describe 'Replace-StartMenuForAllUsers guard paths' {
BeforeEach {
$script:Params = @{}
$script:AssetsPath = $TestDrive
Mock Get-UserDirectory { Join-Path $TestDrive 'Users' }
Mock Get-ChildItem { @() }
Mock Replace-StartMenu {}
Mock New-Item {}
Mock Write-Host {}
}
It 'does not touch profiles when the template is missing' {
Replace-StartMenuForAllUsers -startMenuTemplate (Join-Path $TestDrive 'missing.bin')
Should -Invoke Get-UserDirectory -Times 0 -Exactly
Should -Invoke Replace-StartMenu -Times 0 -Exactly
}
It 'does not create or replace the Default profile in WhatIf mode' {
$template = Join-Path $TestDrive 'template.bin'
Set-Content -LiteralPath $template -Value 'template'
$script:Params = @{ WhatIf = $true }
Mock Test-Path { param($Path) $Path -eq $template }
Replace-StartMenuForAllUsers -startMenuTemplate $template
Should -Invoke New-Item -Times 0 -Exactly
Should -Invoke Replace-StartMenu -Times 0 -Exactly
}
}