From 025e417898809c016a677ab014c2e50c5389acb4 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Tue, 12 May 2026 00:24:48 -0400 Subject: [PATCH 1/2] style: align test scaffolding with canonical PSMTplt Apply the three style rules from PowerShellModuleTemplate#23 to the Help/Meta/MetaFixers test files this repo inherited from the template: - Named parameters on multi-arg cmdlet calls (Split-Path, Join-Path, Test-Path, Get-Module, Get-Content, Select-String, Get-TextFilesList, Test-FileUnicode) - ValidateNotNull / ValidateNotNullOrEmpty validators on mandatory param entries in tests/MetaFixers.psm1 - Test-FileUnicode call inside Get-UnicodeFilesList now uses named -FileInfo parameter Also restores the PR #23-era multi-paramset mandatory-skip block on the 'Has correct [mandatory] value' It in Help.tests.ps1 (this repo was carrying the pre-#23 version that doesn't handle parameters with varying IsMandatory status across parameter sets), and fixes a stale $parameterNames reference in the last Context block (should be $commandParameterNames). Both bundled in per the cross-repo audit. tests/Manifest.tests.ps1 is the older Module Dependency variant (no Test-VersionConstraint helper, -Child typo on Join-Path) and is deferred to a separate uplift PR. Behavior is unchanged for parameters with consistent IsMandatory across sets; previously-failing-or-flaky tests on multi-paramset parameters will now skip with a clear reason. --- tests/Help.tests.ps1 | 34 +++++++++++++++++++++++----------- tests/Meta.tests.ps1 | 6 +++--- tests/MetaFixers.psm1 | 6 +++++- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/tests/Help.tests.ps1 b/tests/Help.tests.ps1 index 859d5c9..074cac7 100644 --- a/tests/Help.tests.ps1 +++ b/tests/Help.tests.ps1 @@ -72,7 +72,7 @@ BeforeDiscovery { # the values it needs (BHPSModuleManifest, BHProjectName) — when running # via ./build.ps1 this happens before psake; running tests in isolation # bypasses that, so we do it here. - Set-BuildEnvironment -Path (Split-Path -Parent $PSScriptRoot) -Force + Set-BuildEnvironment -Path (Split-Path -Path $PSScriptRoot -Parent) -Force $buildFilePath = Join-Path -Path $PSScriptRoot -ChildPath '..\build.psake.ps1' $invokePsakeParameters = @{ TaskList = 'Build' @@ -82,10 +82,10 @@ BeforeDiscovery { } # PowerShellBuild outputs to Output///, override BHBuildOutput - $projectRoot = Split-Path -Parent $PSScriptRoot - $sourceManifest = Join-Path $projectRoot "$Env:BHProjectName/$Env:BHProjectName.psd1" + $projectRoot = Split-Path -Path $PSScriptRoot -Parent + $sourceManifest = Join-Path -Path $projectRoot -ChildPath "$Env:BHProjectName/$Env:BHProjectName.psd1" $moduleVersion = (Import-PowerShellDataFile -Path $sourceManifest).ModuleVersion - $Env:BHBuildOutput = Join-Path $projectRoot "Output/$Env:BHProjectName/$moduleVersion" + $Env:BHBuildOutput = Join-Path -Path $projectRoot -ChildPath "Output/$Env:BHProjectName/$moduleVersion" # Define the path to the module manifest $moduleManifestFilename = $Env:BHProjectName + '.psd1' @@ -97,18 +97,18 @@ BeforeDiscovery { 'Classes' ) | ForEach-Object { $path = Join-Path -Path $Env:BHBuildOutput -ChildPath $_ - if (Test-Path $path) { + if (Test-Path -Path $path) { $global:CustomTypes += (Get-ChildItem -Path $path -Recurse -ErrorAction 'SilentlyContinue').BaseName } } # Remove all versions of the module from the session. Pester can't handle multiple versions. - Get-Module $Env:BHProjectName | Remove-Module -Force -ErrorAction 'Ignore' + Get-Module -Name $Env:BHProjectName | Remove-Module -Force -ErrorAction 'Ignore' Import-Module -Name $moduleManifestPath -Verbose:$false -ErrorAction 'Stop' # Get module commands $getCommandParameters = @{ - Module = (Get-Module $Env:BHProjectName) + Module = (Get-Module -Name $Env:BHProjectName) CommandType = [System.Management.Automation.CommandTypes[]]'Cmdlet, Function' # Not alias } if ($PSVersionTable.PSVersion.Major -lt 6) { @@ -130,7 +130,7 @@ BeforeAll { # the values it needs (BHPSModuleManifest, BHProjectName) — when running # via ./build.ps1 this happens before psake; running tests in isolation # bypasses that, so we do it here. - Set-BuildEnvironment -Path (Split-Path -Parent $PSScriptRoot) -Force + Set-BuildEnvironment -Path (Split-Path -Path $PSScriptRoot -Parent) -Force $buildFilePath = Join-Path -Path $PSScriptRoot -ChildPath '..\build.psake.ps1' $invokePsakeParameters = @{ TaskList = 'Build' @@ -212,8 +212,20 @@ Describe "Test help for <_.Name>" -ForEach $commands { # Required value in Help should match IsMandatory property of parameter It 'Has correct [mandatory] value' { - $codeMandatory = $_.IsMandatory.toString() - $parameterHelp.Required | Should -Be $codeMandatory + # Skip parameters that have different mandatory status across parameter sets + $parameterSetsWithParam = $command.ParameterSets | Where-Object { $_.Parameters.Name -contains $parameterName } + $mandatoryValues = $parameterSetsWithParam | ForEach-Object { + ($_.Parameters | Where-Object { $_.Name -eq $parameterName }).IsMandatory + } | Sort-Object -Unique + + if ($mandatoryValues.Count -gt 1) { + Set-ItResult -Skipped -Because "Parameter '$parameterName' has varying mandatory status across parameter sets" + return + } + + $codeMandatory = $_.IsMandatory.toString().ToLower() + $helpRequired = $parameterHelp.Required.ToLower() + $helpRequired | Should -Be $codeMandatory } # Parameter type in help should match code @@ -233,7 +245,7 @@ Describe "Test help for <_.Name>" -ForEach $commands { # Shouldn't find extra parameters in help It 'finds help parameter in code: <_>' { - $_ -in $parameterNames | Should -Be $true + $_ -in $commandParameterNames | Should -Be $true } } } diff --git a/tests/Meta.tests.ps1 b/tests/Meta.tests.ps1 index 68298f0..c1813ec 100644 --- a/tests/Meta.tests.ps1 +++ b/tests/Meta.tests.ps1 @@ -9,11 +9,11 @@ BeforeAll { $projectRoot = $PSScriptRoot } - $allTextFiles = Get-TextFilesList $projectRoot + $allTextFiles = Get-TextFilesList -Root $projectRoot $unicodeFilesCount = 0 $totalTabsCount = 0 foreach ($textFile in $allTextFiles) { - if (Test-FileUnicode $textFile) { + if (Test-FileUnicode -FileInfo $textFile) { $unicodeFilesCount++ Write-Warning ( "File $($textFile.FullName) contains 0x00 bytes." + @@ -24,7 +24,7 @@ BeforeAll { $unicodeFilesCount | Should -Be 0 $fileName = $textFile.FullName - (Get-Content $fileName -Raw) | Select-String "`t" | Foreach-Object { + (Get-Content -Path $fileName -Raw) | Select-String -Pattern "`t" | Foreach-Object { Write-Warning ( "There are tabs in $fileName." + ' Use Fixer "Get-TextFilesList `$pwd | ConvertTo-SpaceIndentation".' diff --git a/tests/MetaFixers.psm1 b/tests/MetaFixers.psm1 index 7dec0c8..43da225 100644 --- a/tests/MetaFixers.psm1 +++ b/tests/MetaFixers.psm1 @@ -27,6 +27,7 @@ function ConvertTo-UTF8 { [OutputType([void])] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [ValidateNotNull()] [System.IO.FileInfo]$FileInfo ) @@ -56,6 +57,7 @@ function ConvertTo-SpaceIndentation { [OutputType([void])] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [ValidateNotNull()] [System.IO.FileInfo]$FileInfo ) @@ -85,6 +87,7 @@ function Get-TextFilesList { [OutputType([System.IO.FileInfo])] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [ValidateNotNullOrEmpty()] [string]$Root ) @@ -159,10 +162,11 @@ function Get-UnicodeFilesList { [OutputType([System.IO.FileInfo])] param( [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] [string]$Root ) $root | Get-TextFilesList | Where-Object { - Test-FileUnicode $_ + Test-FileUnicode -FileInfo $_ } } From 26db59f79b737f906d1ddfd96192ae6938f737cf Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Wed, 27 May 2026 00:02:16 -0400 Subject: [PATCH 2/2] style: scope named parameters to multi-arg calls in test scaffolding Align tests/Help.tests.ps1, tests/Meta.tests.ps1, and tests/MetaFixers.psm1 with the scoped named-parameter rule the template adopted in PowerShellModuleTemplate#36 (ai-agent-instruction-modules#25): name parameters only on calls passing two or more arguments; single-argument calls stay positional. Reverts the over-naming an earlier revision of this branch had added. Test-Path, Get-Module, Get-Help, Get-TextFilesList, Test-FileUnicode, Select-String, Import-Module, Import-PowerShellDataFile, and FilterOutCommonParameters single-argument calls go back to positional, matching the canonical template line-for-line. Multi-argument and trailing-switch calls keep their names (Split-Path -Path $x -Parent, Join-Path, Get-ChildItem -Path $x -Recurse, Get-Content -Path $x -Raw). The MetaFixers validation attributes and the multi-paramset mandatory-skip block are unchanged. Build + Pester pass locally: 785 passed, 0 failed. Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/Help.tests.ps1 | 22 +++++++++++----------- tests/Meta.tests.ps1 | 8 ++++---- tests/MetaFixers.psm1 | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/Help.tests.ps1 b/tests/Help.tests.ps1 index 2ab2f2b..836f1c9 100644 --- a/tests/Help.tests.ps1 +++ b/tests/Help.tests.ps1 @@ -84,7 +84,7 @@ BeforeDiscovery { # PowerShellBuild outputs to Output///, override BHBuildOutput $projectRoot = Split-Path -Path $PSScriptRoot -Parent $sourceManifest = Join-Path -Path $projectRoot -ChildPath "$Env:BHProjectName/$Env:BHProjectName.psd1" - $moduleVersion = (Import-PowerShellDataFile -Path $sourceManifest).ModuleVersion + $moduleVersion = (Import-PowerShellDataFile $sourceManifest).ModuleVersion $Env:BHBuildOutput = Join-Path -Path $projectRoot -ChildPath "Output/$Env:BHProjectName/$moduleVersion" # Define the path to the module manifest @@ -97,18 +97,18 @@ BeforeDiscovery { 'Classes' ) | ForEach-Object { $path = Join-Path -Path $Env:BHBuildOutput -ChildPath $_ - if (Test-Path -Path $path) { + if (Test-Path $path) { $global:CustomTypes += (Get-ChildItem -Path $path -Recurse -ErrorAction 'SilentlyContinue').BaseName } } # Remove all versions of the module from the session. Pester can't handle multiple versions. - Get-Module -Name $Env:BHProjectName | Remove-Module -Force -ErrorAction 'Ignore' - Import-Module -Name $moduleManifestPath -Verbose:$false -ErrorAction 'Stop' + Get-Module $Env:BHProjectName | Remove-Module -Force -ErrorAction 'Ignore' + Import-Module $moduleManifestPath -Verbose:$false -ErrorAction 'Stop' # Get module commands $getCommandParameters = @{ - Module = (Get-Module -Name $Env:BHProjectName) + Module = (Get-Module $Env:BHProjectName) CommandType = [System.Management.Automation.CommandTypes[]]'Cmdlet, Function' # Not alias } if ($PSVersionTable.PSVersion.Major -lt 6) { @@ -148,10 +148,10 @@ Describe "Test help for <_.Name>" -ForEach $commands { # -ForEach, which Pester evaluates during discovery (before BeforeAll runs). $command = $_ $commandName = $command.Name - $commandHelp = Get-Help -Name $command.Name -ErrorAction 'SilentlyContinue' - $commandParameters = global:FilterOutCommonParameters -Parameters $command.ParameterSets.Parameters + $commandHelp = Get-Help $command.Name -ErrorAction 'SilentlyContinue' + $commandParameters = global:FilterOutCommonParameters $command.ParameterSets.Parameters $commandParameterNames = $commandParameters.Name - $helpParameters = global:FilterOutCommonParameters -Parameters $commandHelp.Parameters.Parameter + $helpParameters = global:FilterOutCommonParameters $commandHelp.Parameters.Parameter $helpParameterNames = $helpParameters.Name $helpLinks = $commandHelp.relatedLinks.navigationLink.uri | Where-Object { $_ -match '^https?://' } } @@ -160,10 +160,10 @@ Describe "Test help for <_.Name>" -ForEach $commands { # These variables are needed in both discovery and test phases so we need to duplicate them here $command = $_ $commandName = $_.Name - $commandHelp = Get-Help -Name $command.Name -ErrorAction 'SilentlyContinue' - $commandParameters = global:FilterOutCommonParameters -Parameters $command.ParameterSets.Parameters + $commandHelp = Get-Help $command.Name -ErrorAction 'SilentlyContinue' + $commandParameters = global:FilterOutCommonParameters $command.ParameterSets.Parameters $commandParameterNames = $commandParameters.Name - $helpParameters = global:FilterOutCommonParameters -Parameters $commandHelp.Parameters.Parameter + $helpParameters = global:FilterOutCommonParameters $commandHelp.Parameters.Parameter $helpParameterNames = $helpParameters.Name } diff --git a/tests/Meta.tests.ps1 b/tests/Meta.tests.ps1 index c1813ec..c3addf4 100644 --- a/tests/Meta.tests.ps1 +++ b/tests/Meta.tests.ps1 @@ -2,18 +2,18 @@ BeforeAll { Set-StrictMode -Version 'Latest' # Make sure MetaFixers.psm1 is loaded - it contains Get-TextFilesList - Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath 'MetaFixers.psm1') -Verbose:$false -Force + Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'MetaFixers.psm1') -Verbose:$false -Force $projectRoot = $Env:BHProjectPath if (-not $projectRoot) { $projectRoot = $PSScriptRoot } - $allTextFiles = Get-TextFilesList -Root $projectRoot + $allTextFiles = Get-TextFilesList $projectRoot $unicodeFilesCount = 0 $totalTabsCount = 0 foreach ($textFile in $allTextFiles) { - if (Test-FileUnicode -FileInfo $textFile) { + if (Test-FileUnicode $textFile) { $unicodeFilesCount++ Write-Warning ( "File $($textFile.FullName) contains 0x00 bytes." + @@ -24,7 +24,7 @@ BeforeAll { $unicodeFilesCount | Should -Be 0 $fileName = $textFile.FullName - (Get-Content -Path $fileName -Raw) | Select-String -Pattern "`t" | Foreach-Object { + (Get-Content -Path $fileName -Raw) | Select-String "`t" | Foreach-Object { Write-Warning ( "There are tabs in $fileName." + ' Use Fixer "Get-TextFilesList `$pwd | ConvertTo-SpaceIndentation".' diff --git a/tests/MetaFixers.psm1 b/tests/MetaFixers.psm1 index 43da225..5c614df 100644 --- a/tests/MetaFixers.psm1 +++ b/tests/MetaFixers.psm1 @@ -167,6 +167,6 @@ function Get-UnicodeFilesList { ) $root | Get-TextFilesList | Where-Object { - Test-FileUnicode -FileInfo $_ + Test-FileUnicode $_ } }