From 67cad662275bc96894ec7b9a4211687d4eda34d9 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 8 Jul 2026 03:44:56 +0200 Subject: [PATCH 1/4] Allow empty -ForEach in type-accelerator tests (Pester 6 compat) Pester 6 defaults Run.FailOnNullOrEmptyForEach to true, so the enum/class type-accelerator It blocks fail Discovery for a fixture module that has classes but no enums (or vice versa). Add -AllowNullOrEmptyForEach so an empty collection is skipped instead of failing the container. Fixes the Action-Test-outputs failure on main. --- src/tests/Module/PSModule/PSModule.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/Module/PSModule/PSModule.Tests.ps1 b/src/tests/Module/PSModule/PSModule.Tests.ps1 index 12c6141..318e875 100644 --- a/src/tests/Module/PSModule/PSModule.Tests.ps1 +++ b/src/tests/Module/PSModule/PSModule.Tests.ps1 @@ -93,12 +93,12 @@ Describe 'PSModule - Module tests' { BeforeAll { Import-Module -Name $moduleManifestPath -Force } - It 'Should register public enum [<_>] as a type accelerator' -ForEach $expectedEnumNames { + It 'Should register public enum [<_>] as a type accelerator' -ForEach $expectedEnumNames -AllowNullOrEmptyForEach { $registered = [psobject].Assembly.GetType('System.Management.Automation.TypeAccelerators')::Get $registered.Keys | Should -Contain $_ -Because 'the framework registers public enums as type accelerators' } - It 'Should register public class [<_>] as a type accelerator' -ForEach $expectedClassNames { + It 'Should register public class [<_>] as a type accelerator' -ForEach $expectedClassNames -AllowNullOrEmptyForEach { $registered = [psobject].Assembly.GetType('System.Management.Automation.TypeAccelerators')::Get $registered.Keys | Should -Contain $_ -Because 'the framework registers public classes as type accelerators' } From e1e116a34be420dfb48a11f310578c31abcb9c5e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 8 Jul 2026 11:27:46 +0200 Subject: [PATCH 2/4] test: cover enum-only type accelerator fixtures --- .github/workflows/Action-Test-outputs.yml | 15 +++++-- .../PSModuleEnumOnly/PSModuleEnumOnly.psd1 | 36 +++++++++++++++ .../PSModuleEnumOnly/PSModuleEnumOnly.psm1 | 45 +++++++++++++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psd1 create mode 100644 tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psm1 diff --git a/.github/workflows/Action-Test-outputs.yml b/.github/workflows/Action-Test-outputs.yml index 2b5b418..c80fd80 100644 --- a/.github/workflows/Action-Test-outputs.yml +++ b/.github/workflows/Action-Test-outputs.yml @@ -16,11 +16,18 @@ permissions: {} jobs: ActionTestOutputs: - name: Action-Test [outputs] - [${{ matrix.os }}] + name: Action-Test [outputs/${{ matrix.fixture.name }}] - [${{ matrix.os }}] strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] + fixture: + - name: PSModuleTest + workingDirectory: tests/outputTestRepo + coveragePercentTarget: 30 + - name: PSModuleEnumOnly + workingDirectory: tests/outputEnumOnlyTestRepo + coveragePercentTarget: 0 runs-on: ${{ matrix.os }} steps: - name: Checkout repo @@ -32,7 +39,7 @@ jobs: uses: ./ id: action-test with: - Name: PSModuleTest - WorkingDirectory: tests/outputTestRepo + Name: ${{ matrix.fixture.name }} + WorkingDirectory: ${{ matrix.fixture.workingDirectory }} Settings: Module - CodeCoverage_CoveragePercentTarget: 30 + CodeCoverage_CoveragePercentTarget: ${{ matrix.fixture.coveragePercentTarget }} diff --git a/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psd1 b/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psd1 new file mode 100644 index 0000000..d968958 --- /dev/null +++ b/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psd1 @@ -0,0 +1,36 @@ +@{ + RootModule = 'PSModuleEnumOnly.psm1' + ModuleVersion = '999.0.0' + CompatiblePSEditions = @( + 'Core' + 'Desktop' + ) + GUID = 'b1c8c046-2253-4f30-8e08-e98a222a954a' + Author = 'PSModule' + CompanyName = 'PSModule' + Copyright = '(c) 2024 PSModule. All rights reserved.' + Description = 'Fixture module with enum type accelerators and no class type accelerators.' + PowerShellVersion = '5.1' + ProcessorArchitecture = 'None' + FunctionsToExport = @() + CmdletsToExport = @() + VariablesToExport = @() + AliasesToExport = @() + FileList = @( + 'PSModuleEnumOnly.psd1' + 'PSModuleEnumOnly.psm1' + ) + PrivateData = @{ + PSData = @{ + Tags = @( + 'workflow' + 'powershell' + 'powershell-module' + 'PSEdition_Desktop' + 'PSEdition_Core' + ) + LicenseUri = 'https://github.com/PSModule/Test-PSModule/blob/main/LICENSE' + ProjectUri = 'https://github.com/PSModule/Test-PSModule' + } + } +} \ No newline at end of file diff --git a/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psm1 b/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psm1 new file mode 100644 index 0000000..57f7291 --- /dev/null +++ b/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psm1 @@ -0,0 +1,45 @@ +[CmdletBinding()] +param() + +enum ModuleLifecycle { + Loaded + Removed +} + +#region Class exporter +$TypeAcceleratorsClass = [psobject].Assembly.GetType( + 'System.Management.Automation.TypeAccelerators' +) +$ExistingTypeAccelerators = $TypeAcceleratorsClass::Get +$ExportableEnums = @( + [ModuleLifecycle] +) +$ExportableEnums | ForEach-Object { Write-Verbose "Exporting enum '$($_.FullName)'." } +foreach ($Type in $ExportableEnums) { + if ($Type.FullName -in $ExistingTypeAccelerators.Keys) { + Write-Verbose "Enum already exists [$($Type.FullName)]. Skipping." + } else { + Write-Verbose "Importing enum '$Type'." + $TypeAcceleratorsClass::Add($Type.FullName, $Type) + } +} +$ExportableClasses = @( +) +$ExportableClasses | ForEach-Object { Write-Verbose "Exporting class '$($_.FullName)'." } +foreach ($Type in $ExportableClasses) { + if ($Type.FullName -in $ExistingTypeAccelerators.Keys) { + Write-Verbose "Class already exists [$($Type.FullName)]. Skipping." + } else { + Write-Verbose "Importing class '$Type'." + $TypeAcceleratorsClass::Add($Type.FullName, $Type) + } +} + +$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { + foreach ($Type in ($ExportableEnums + $ExportableClasses)) { + $null = $TypeAcceleratorsClass::Remove($Type.FullName) + } +}.GetNewClosure() +#endregion Class exporter + +Export-ModuleMember -Function @() -Alias @() -Variable @() \ No newline at end of file From a54bd23d3c4b159eeda7af70890a9467097ac2fa Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 8 Jul 2026 11:29:42 +0200 Subject: [PATCH 3/4] test: track enum-only fixture test directory --- tests/outputEnumOnlyTestRepo/tests/.gitkeep | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/outputEnumOnlyTestRepo/tests/.gitkeep diff --git a/tests/outputEnumOnlyTestRepo/tests/.gitkeep b/tests/outputEnumOnlyTestRepo/tests/.gitkeep new file mode 100644 index 0000000..9317287 --- /dev/null +++ b/tests/outputEnumOnlyTestRepo/tests/.gitkeep @@ -0,0 +1 @@ +Tracks the fixture tests directory required by the action setup step. \ No newline at end of file From 646db241bfe14af431c0a53e5b7b91e76996b067 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 8 Jul 2026 11:39:11 +0200 Subject: [PATCH 4/4] test: guard enum fixture accelerator cleanup --- .../outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psm1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psm1 b/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psm1 index 57f7291..3572478 100644 --- a/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psm1 +++ b/tests/outputEnumOnlyTestRepo/outputs/module/PSModuleEnumOnly/PSModuleEnumOnly.psm1 @@ -36,8 +36,11 @@ foreach ($Type in $ExportableClasses) { } $MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { + $CurrentTypeAccelerators = $TypeAcceleratorsClass::Get foreach ($Type in ($ExportableEnums + $ExportableClasses)) { - $null = $TypeAcceleratorsClass::Remove($Type.FullName) + if ($CurrentTypeAccelerators[$Type.FullName] -eq $Type) { + $null = $TypeAcceleratorsClass::Remove($Type.FullName) + } } }.GetNewClosure() #endregion Class exporter