2026-08-22 05:43:55 +10:00
|
|
|
BeforeAll {
|
|
|
|
|
$script:RepoRoot = Join-Path $PSScriptRoot '..'
|
|
|
|
|
$script:FeaturesPath = Join-Path $script:RepoRoot 'Config\Features.json'
|
|
|
|
|
$script:Win11DebloatPath = Join-Path $script:RepoRoot 'Win11Debloat.ps1'
|
|
|
|
|
$script:GetScriptPath = Join-Path $script:RepoRoot 'Scripts\Get.ps1'
|
|
|
|
|
$script:RegfilesPath = Join-Path $script:RepoRoot 'Regfiles'
|
|
|
|
|
$script:Features = @((Get-Content -LiteralPath $script:FeaturesPath -Raw | ConvertFrom-Json).Features)
|
|
|
|
|
$script:LauncherOnlyParameters = @('Dev', 'Verbose', 'WhatIf')
|
|
|
|
|
|
|
|
|
|
function Get-ScriptParameterNames {
|
|
|
|
|
param(
|
|
|
|
|
[Parameter(Mandatory)]
|
|
|
|
|
[string]$Path
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$tokens = $null
|
|
|
|
|
$parseErrors = $null
|
|
|
|
|
$ast = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$tokens, [ref]$parseErrors)
|
|
|
|
|
$parseErrors | Should -BeNullOrEmpty
|
|
|
|
|
|
|
|
|
|
@($ast.ParamBlock.Parameters | ForEach-Object { $_.Name.VariablePath.UserPath })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Describe 'FeatureId parameter contracts' {
|
|
|
|
|
It 'declares every FeatureId as a parameter on Win11Debloat.ps1' {
|
|
|
|
|
$parameterNames = Get-ScriptParameterNames -Path $script:Win11DebloatPath
|
|
|
|
|
$missing = @($script:Features.FeatureId | Where-Object { $parameterNames -notcontains $_ })
|
|
|
|
|
|
|
|
|
|
$missing | Should -HaveCount 0 -Because ($missing -join ', ')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'declares every FeatureId as a parameter on Scripts/Get.ps1' {
|
|
|
|
|
$parameterNames = Get-ScriptParameterNames -Path $script:GetScriptPath
|
|
|
|
|
$missing = @($script:Features.FeatureId | Where-Object { $parameterNames -notcontains $_ })
|
|
|
|
|
|
|
|
|
|
$missing | Should -HaveCount 0 -Because ($missing -join ', ')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'keeps Scripts/Get.ps1 aligned with Win11Debloat.ps1 plus launcher-only switches' {
|
|
|
|
|
$win11DebloatParameters = Get-ScriptParameterNames -Path $script:Win11DebloatPath
|
|
|
|
|
$getParameters = Get-ScriptParameterNames -Path $script:GetScriptPath
|
|
|
|
|
$missingFromGet = @($win11DebloatParameters | Where-Object { $getParameters -notcontains $_ })
|
|
|
|
|
$missingLauncherOnly = @(
|
|
|
|
|
$script:LauncherOnlyParameters |
|
|
|
|
|
Where-Object { $getParameters -notcontains $_ }
|
|
|
|
|
)
|
|
|
|
|
$unexpectedOnGet = @(
|
|
|
|
|
$getParameters |
|
|
|
|
|
Where-Object { $win11DebloatParameters -notcontains $_ -and $script:LauncherOnlyParameters -notcontains $_ }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$missingFromGet | Should -HaveCount 0 -Because ($missingFromGet -join ', ')
|
|
|
|
|
$missingLauncherOnly | Should -HaveCount 0 -Because ($missingLauncherOnly -join ', ')
|
|
|
|
|
$unexpectedOnGet | Should -HaveCount 0 -Because ($unexpectedOnGet -join ', ')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'keeps every RegistryKey file in Regfiles and Regfiles/Sysprep' {
|
|
|
|
|
$missing = @(
|
|
|
|
|
foreach ($feature in $script:Features) {
|
|
|
|
|
if ([string]::IsNullOrWhiteSpace($feature.RegistryKey)) { continue }
|
|
|
|
|
|
|
|
|
|
$applyPath = Join-Path $script:RegfilesPath $feature.RegistryKey
|
|
|
|
|
$sysprepPath = Join-Path (Join-Path $script:RegfilesPath 'Sysprep') $feature.RegistryKey
|
|
|
|
|
if (-not (Test-Path -LiteralPath $applyPath -PathType Leaf)) {
|
|
|
|
|
"$($feature.FeatureId) missing Regfiles\$($feature.RegistryKey)"
|
|
|
|
|
}
|
|
|
|
|
if (-not (Test-Path -LiteralPath $sysprepPath -PathType Leaf)) {
|
|
|
|
|
"$($feature.FeatureId) missing Regfiles\Sysprep\$($feature.RegistryKey)"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$missing | Should -HaveCount 0 -Because ($missing -join '; ')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'keeps every RegistryUndoKey file in Regfiles/Undo or Regfiles' {
|
|
|
|
|
$missing = @(
|
|
|
|
|
foreach ($feature in $script:Features) {
|
|
|
|
|
if ([string]::IsNullOrWhiteSpace($feature.RegistryUndoKey)) { continue }
|
|
|
|
|
|
|
|
|
|
$undoPath = Join-Path (Join-Path $script:RegfilesPath 'Undo') $feature.RegistryUndoKey
|
|
|
|
|
$rootPath = Join-Path $script:RegfilesPath $feature.RegistryUndoKey
|
|
|
|
|
if (-not ((Test-Path -LiteralPath $undoPath -PathType Leaf) -or (Test-Path -LiteralPath $rootPath -PathType Leaf))) {
|
|
|
|
|
"$($feature.FeatureId) missing undo file $($feature.RegistryUndoKey)"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$missing | Should -HaveCount 0 -Because ($missing -join '; ')
|
|
|
|
|
}
|
2026-10-08 04:45:49 +07:00
|
|
|
|
|
|
|
|
It 'has an en-US Features translation with a Label for every FeatureId' {
|
|
|
|
|
$enUsPath = Join-Path $script:RepoRoot 'Config\Languages\en-US\Features.json'
|
|
|
|
|
$translations = (Get-Content -LiteralPath $enUsPath -Raw | ConvertFrom-Json).Features
|
|
|
|
|
$missing = @(
|
|
|
|
|
foreach ($feature in $script:Features) {
|
|
|
|
|
$entry = $translations.PSObject.Properties[$feature.FeatureId]
|
|
|
|
|
if ($null -eq $entry -or [string]::IsNullOrWhiteSpace($entry.Value.Label)) {
|
|
|
|
|
$feature.FeatureId
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$missing | Should -HaveCount 0 -Because ($missing -join ', ')
|
|
|
|
|
}
|
2026-10-09 02:59:54 +07:00
|
|
|
|
|
|
|
|
It 'accounts for every Win11Debloat.ps1 parameter as a FeatureId or a control parameter' {
|
|
|
|
|
$tokens = $null
|
|
|
|
|
$parseErrors = $null
|
|
|
|
|
$ast = [System.Management.Automation.Language.Parser]::ParseFile($script:Win11DebloatPath, [ref]$tokens, [ref]$parseErrors)
|
|
|
|
|
$parseErrors | Should -BeNullOrEmpty
|
|
|
|
|
|
|
|
|
|
$assignment = $ast.Find({
|
|
|
|
|
param($node)
|
|
|
|
|
$node -is [System.Management.Automation.Language.AssignmentStatementAst] -and $node.Left.Extent.Text -eq '$script:ControlParams'
|
|
|
|
|
}, $true)
|
|
|
|
|
$assignment | Should -Not -BeNullOrEmpty
|
|
|
|
|
|
|
|
|
|
$controlParameters = @(
|
|
|
|
|
$assignment.Right.FindAll({ param($node) $node -is [System.Management.Automation.Language.StringConstantExpressionAst] }, $true) |
|
|
|
|
|
ForEach-Object { $_.Value }
|
|
|
|
|
)
|
|
|
|
|
$unaccounted = @(
|
|
|
|
|
Get-ScriptParameterNames -Path $script:Win11DebloatPath |
|
|
|
|
|
Where-Object { $script:Features.FeatureId -notcontains $_ -and $controlParameters -notcontains $_ }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$unaccounted | Should -HaveCount 0 -Because ($unaccounted -join ', ')
|
|
|
|
|
}
|
2026-08-22 05:43:55 +10:00
|
|
|
}
|