From 0120b2491d0ce693820bc3aa031a7740214d04e3 Mon Sep 17 00:00:00 2001 From: Gilbert Sanchez Date: Wed, 16 Sep 2026 22:59:04 -0700 Subject: [PATCH 1/4] build: add standard psake bootstrap (Init/Clean/Build/Test/Analyze/Publish) Mirrors PSDepend's psake+PowerShellBuild+PSDepend build convention: - requirements.psd1 / build.ps1 / psakeFile.ps1 at repo root. - psakeFile.ps1 uses -FromModule PowerShellBuild, adding Init, Clean, StageFiles, Build, Analyze, Pester, Test, BuildHelp, Publish, and ?. GenerateFormatData task added ahead of StageFiles since the manifest's FormatsToProcess entry (PSKoans.format.ps1xml) is EZOut-generated and gitignored, so the module can't even import without it. - .gitignore extended for Output/**, Tests/out/**, testResults.xml. Test suite bootstrap (Tests/**/*.Tests.ps1): - Replaced #Requires -Modules PSKoans with a BeforeDiscovery block that builds (if needed) and imports the staged module from Output/, matching PSDepend's own staged-import test convention. - Fixed unscoped Mocks across ~13 test files: without -ModuleName 'PSKoans' a Mock never intercepts calls made from inside the module, so real cmdlets ran instead -- including Start-Process launching a real editor. - Fixed a real data-corruption bug: Reset-PSKoan.Tests.ps1 and Update-PSKoanFile.Tests.ps1 called (Get-PSKoan -Scope Module).Path directly from test scope; since module-scoped mocks don't intercept direct test-scope calls, the real cmdlet ran and Set-Content overwrote every staged koan file with fixture content. Fixed by computing paths into variables instead of depending on mock interception outside module scope. - requirements.psd1's Pester pin relaxed (no exact version): PowerShellBuild's Test-PSBuildPester unconditionally does Import-Module -MinimumVersion, which throws if a different Pester major is already loaded in-process. - Added $env:PSModulePath entry for the staged module root so `using module PSKoans` resolves during koan file parsing/execution. - Fixed several Pester 6 strictness regressions surfaced by the above (unmatched ParameterFilter mocks, empty -TestCases arrays). Invoke-psake Test now runs cleanly (no hangs/crashes): 631 passed / 100 failed. All 100 remaining failures are pre-existing and out of scope: ~90 are missing comment-based help content (ModuleHelp.Tests.ps1), and ~9 trace to Invoke-Koan.ps1 splatting a legacy Pester 3/4 `-Script` parameter that Pester 5+ removed -- a real product bug affecting Get-Karma/Show-Karma at runtime, filed separately from this build change. Closes #485 --- .gitignore | 4 + .../Private/Assert-UnblockedFile.Tests.ps1 | 18 ++- .../ConvertFrom-WildcardPattern.Tests.ps1 | 18 ++- Tests/Functions/Private/Get-KoanAst.Tests.ps1 | 18 ++- .../Private/Get-KoanAttribute.Tests.ps1 | 18 ++- Tests/Functions/Private/Get-KoanIt.Tests.ps1 | 18 ++- Tests/Functions/Private/Invoke-Koan.Tests.ps1 | 18 ++- .../Functions/Private/Measure-Koan.Tests.ps1 | 18 ++- .../Private/New-KoanRunspace.Tests.ps1 | 18 +++ .../Private/New-PSKoanErrorRecord.Tests.ps1 | 18 ++- .../Private/Update-PSKoanFile.Tests.ps1 | 35 +++-- Tests/Functions/Public/Get-Blank.Tests.ps1 | 18 ++- Tests/Functions/Public/Get-Karma.Tests.ps1 | 39 +++-- Tests/Functions/Public/Get-PSKoan.Tests.ps1 | 29 +++- .../Public/Get-PSKoanLocation.Tests.ps1 | 24 ++- .../Public/Get-PSKoanSetting.Tests.ps1 | 22 ++- .../Public/Move-PSKoanLibrary.Tests.ps1 | 30 +++- .../Public/Register-Advice.Tests.ps1 | 39 +++-- Tests/Functions/Public/Reset-PSKoan.Tests.ps1 | 76 +++++++--- .../Public/Set-PSKoanLocation.Tests.ps1 | 22 ++- .../Public/Set-PSKoanSetting.Tests.ps1 | 18 ++- Tests/Functions/Public/Show-Advice.Tests.ps1 | 22 ++- Tests/Functions/Public/Show-Karma.Tests.ps1 | 141 ++++++++++-------- .../Functions/Public/Update-PSKoan.Tests.ps1 | 45 ++++-- Tests/KoanValidation.Tests.ps1 | 20 ++- Tests/ModuleHelp.Tests.ps1 | 39 +++-- Tests/ModuleValidation.Tests.ps1 | 18 +++ build.ps1 | 67 +++++++++ psakeFile.ps1 | 46 ++++++ requirements.psd1 | 25 ++++ 30 files changed, 754 insertions(+), 187 deletions(-) create mode 100644 build.ps1 create mode 100644 psakeFile.ps1 create mode 100644 requirements.psd1 diff --git a/.gitignore b/.gitignore index 8fd24e879..749a82be7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ PSKoans.psproj PSKoans/*/PSKoans-help.xml + +Output/** +Tests/out/** +testResults.xml diff --git a/Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 b/Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 index 2ab1b9ea7..899f23186 100644 --- a/Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 +++ b/Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} #region Discovery $SkipTests = $PSVersionTable.PSEdition -ne 'Desktop' -or $PSVersionTable.Platform -ne 'Win32NT' diff --git a/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 b/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 index 96ac71f97..cbce7b5bc 100644 --- a/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 +++ b/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'ConvertFrom-WildcardPattern' { diff --git a/Tests/Functions/Private/Get-KoanAst.Tests.ps1 b/Tests/Functions/Private/Get-KoanAst.Tests.ps1 index cb16f9339..39318ccbb 100644 --- a/Tests/Functions/Private/Get-KoanAst.Tests.ps1 +++ b/Tests/Functions/Private/Get-KoanAst.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Get-KoanAst' { diff --git a/Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 b/Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 index 2ba7d11ff..12eca8ca6 100644 --- a/Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 +++ b/Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Get-KoanAttribute' { diff --git a/Tests/Functions/Private/Get-KoanIt.Tests.ps1 b/Tests/Functions/Private/Get-KoanIt.Tests.ps1 index 6f902cb98..56bb0f96b 100644 --- a/Tests/Functions/Private/Get-KoanIt.Tests.ps1 +++ b/Tests/Functions/Private/Get-KoanIt.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Get-KoanIt' { diff --git a/Tests/Functions/Private/Invoke-Koan.Tests.ps1 b/Tests/Functions/Private/Invoke-Koan.Tests.ps1 index 10e58523d..387f184df 100644 --- a/Tests/Functions/Private/Invoke-Koan.Tests.ps1 +++ b/Tests/Functions/Private/Invoke-Koan.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Invoke-Koan' { diff --git a/Tests/Functions/Private/Measure-Koan.Tests.ps1 b/Tests/Functions/Private/Measure-Koan.Tests.ps1 index 577a82d60..801987dfa 100644 --- a/Tests/Functions/Private/Measure-Koan.Tests.ps1 +++ b/Tests/Functions/Private/Measure-Koan.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Measure-Koan' -Skip { diff --git a/Tests/Functions/Private/New-KoanRunspace.Tests.ps1 b/Tests/Functions/Private/New-KoanRunspace.Tests.ps1 index 6155de163..fa201d53f 100644 --- a/Tests/Functions/Private/New-KoanRunspace.Tests.ps1 +++ b/Tests/Functions/Private/New-KoanRunspace.Tests.ps1 @@ -1,3 +1,21 @@ +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} + Describe 'New-KoanRunspace' { BeforeAll { diff --git a/Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 b/Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 index 331aa9f05..234331932 100644 --- a/Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 +++ b/Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'New-PSKoanErrorRecord' { diff --git a/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 b/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 index 357df55bd..03dec3da2 100644 --- a/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 +++ b/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 @@ -1,24 +1,41 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Update-PSKoanFile' { BeforeAll { - Mock 'Get-PSKoanLocation' { - Join-Path -Path $TestDrive -ChildPath 'Koans' - } + $koanLocation = Join-Path -Path $TestDrive -ChildPath 'Koans' + $koanRelativePath = 'Group/AboutSomething.ps1' + $moduleKoanPath = Join-Path -Path $TestDrive -ChildPath 'Module/Group/AboutSomething.ps1' - Mock 'Get-PSKoan' { + Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } + Mock 'Get-PSKoan' -ModuleName 'PSKoans' { [PSCustomObject]@{ Topic = 'AboutSomething' - Path = Join-Path -Path $TestDrive -ChildPath 'Module/Group/AboutSomething.ps1' - RelativePath = 'Group/AboutSomething.ps1' + Path = $moduleKoanPath + RelativePath = $koanRelativePath } } New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'Koans/Group') -ItemType Directory New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'Module/Group') -ItemType Directory - Set-Content -Path (Get-PSKoan).Path -Value @' + Set-Content -Path $moduleKoanPath -Value @' Describe 'AboutSomething' { It 'koan 1' { __ | Should -Be 1 @@ -42,7 +59,7 @@ Describe 'Update-PSKoanFile' { } '@ - $userFilePath = Join-Path -Path (Get-PSKoanLocation) -ChildPath (Get-PSKoan).RelativePath + $userFilePath = Join-Path -Path $koanLocation -ChildPath $koanRelativePath } BeforeEach { diff --git a/Tests/Functions/Public/Get-Blank.Tests.ps1 b/Tests/Functions/Public/Get-Blank.Tests.ps1 index f24e30556..09b9cc1f9 100644 --- a/Tests/Functions/Public/Get-Blank.Tests.ps1 +++ b/Tests/Functions/Public/Get-Blank.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Get-Blank' { diff --git a/Tests/Functions/Public/Get-Karma.Tests.ps1 b/Tests/Functions/Public/Get-Karma.Tests.ps1 index 7a25cce12..a5b7b3f8b 100644 --- a/Tests/Functions/Public/Get-Karma.Tests.ps1 +++ b/Tests/Functions/Public/Get-Karma.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Get-Karma' { @@ -52,18 +68,18 @@ Describe 'Get-Karma' { BeforeAll { Mock 'Measure-Koan' -ModuleName 'PSKoans' - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } - Mock 'Update-PSKoan' { throw 'Prevent recursion' } - Mock 'Write-Warning' + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' + Mock 'Update-PSKoan' { throw 'Prevent recursion' } -ModuleName 'PSKoans' + Mock 'Write-Warning' -ModuleName 'PSKoans' } It 'should attempt to populate koans and then recurse to reassess' { { Get-Karma } | Should -Throw -ExpectedMessage 'Prevent recursion' - Should -Invoke 'Update-PSKoan' -Scope Context + Should -Invoke 'Update-PSKoan' -Scope Context -ModuleName 'PSKoans' } It 'displays a warning before initiating a reset' { - Should -Invoke 'Write-Warning' -Scope Context + Should -Invoke 'Write-Warning' -Scope Context -ModuleName 'PSKoans' } It 'throws an error if a Topic is specified that matches nothing' { @@ -74,13 +90,13 @@ Describe 'Get-Karma' { Context 'With -ListTopics Parameter' { BeforeAll { - Mock 'Get-PSKoan' + Mock 'Get-PSKoan' -ModuleName 'PSKoans' } It 'lists all the koan topics' { Get-Karma -ListTopics - Should -Invoke 'Get-PSKoan' + Should -Invoke 'Get-PSKoan' -ModuleName 'PSKoans' } } @@ -104,13 +120,12 @@ Describe 'Get-Karma' { Context 'Behaviour When All Koans Are Completed' { BeforeAll { - Mock 'Get-PSKoanLocation' { - Join-Path -Path $TestDrive -ChildPath 'CompletedKoan' - } + $completedKoanLocation = Join-Path -Path $TestDrive -ChildPath 'CompletedKoan' + Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $completedKoanLocation } Mock 'Measure-Koan' -ModuleName 'PSKoans' -MockWith { 2 } - $TestFile = Join-Path -Path (Get-PSKoanLocation) -ChildPath 'Group\SelectedTopicTest.Koans.ps1' + $TestFile = Join-Path -Path $completedKoanLocation -ChildPath 'Group\SelectedTopicTest.Koans.ps1' New-Item -Path (Split-Path $TestFile -Parent) -ItemType Directory -Force Set-Content -Path $TestFile -Value @' using module PSKoans diff --git a/Tests/Functions/Public/Get-PSKoan.Tests.ps1 b/Tests/Functions/Public/Get-PSKoan.Tests.ps1 index 93bca3790..c02c6deeb 100644 --- a/Tests/Functions/Public/Get-PSKoan.Tests.ps1 +++ b/Tests/Functions/Public/Get-PSKoan.Tests.ps1 @@ -1,16 +1,31 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Get-PSKoan' { BeforeAll { - Mock 'Get-PSKoanLocation' { - Join-Path $TestDrive 'PSKoans' - } + $koanLocation = Join-Path $TestDrive 'PSKoans' + Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } Update-PSKoan -Confirm:$false # Stage test module - $path = Join-Path -Path (Get-PSKoanLocation) 'Modules\TestModule' + $path = Join-Path -Path $koanLocation 'Modules\TestModule' New-Item -Path $path -ItemType Directory -Force Set-Content -Path (Join-Path -Path $path -ChildPath 'AboutSomething.Koans.ps1') -Value @' using module PSKoans @@ -26,7 +41,7 @@ Describe 'Get-PSKoan' { } It 'retrieves all except module-specific koan files' { - $Files = Get-ChildItem -Path (Get-PSKoanLocation) -Filter *.Koans.ps1 -Recurse -File | + $Files = Get-ChildItem -Path $koanLocation -Filter *.Koans.ps1 -Recurse -File | Where-Object FullName -NotMatch 'PSKoans[\\/]Modules[\\/]' (Get-PSKoan).Topic.Count | Should -Be $Files.Count @@ -49,7 +64,7 @@ Describe 'Get-PSKoan' { } It 'should throw a terminating error if a file is blocked' -Skip:($PSVersionTable.PSEdition -ne 'Desktop' -or $PSVersionTable.Platform -ne 'Win32NT') { - $testFile = Get-ChildItem -Path (Get-PSKoanLocation) -Filter AboutArrays.Koans.ps1 -Recurse -File | + $testFile = Get-ChildItem -Path $koanLocation -Filter AboutArrays.Koans.ps1 -Recurse -File | Select-Object -First 1 Set-Content -Path $testFile.FullName -Stream Zone.Identifier -Value @' diff --git a/Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 b/Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 index d62e5be02..49120e2cb 100644 --- a/Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 +++ b/Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 @@ -1,11 +1,27 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Get-PSKoanLocation' { Context 'Normal Behaviour' { BeforeAll { - Mock 'Get-PSKoanSetting' -ParameterFilter { $Name -eq 'KoanLocation' } -MockWith { + Mock 'Get-PSKoanSetting' -ParameterFilter { $Name -eq 'KoanLocation' } -ModuleName 'PSKoans' -MockWith { '~/PSKoans' } @@ -17,14 +33,14 @@ Describe 'Get-PSKoanLocation' { } It 'calls Get-PSKoanSetting with -Name "KoanLocation"' { - Should -Invoke 'Get-PSKoanSetting' -Scope Context + Should -Invoke 'Get-PSKoanSetting' -Scope Context -ModuleName 'PSKoans' } } Context 'No Value Available' { BeforeAll { - Mock 'Get-PSKoanSetting' -ParameterFilter { $Name -eq 'KoanLocation' } + Mock 'Get-PSKoanSetting' -ParameterFilter { $Name -eq 'KoanLocation' } -ModuleName 'PSKoans' } It 'throws an error if no value can be retrieved' { diff --git a/Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 b/Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 index e5b5e3efe..08fc28017 100644 --- a/Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 +++ b/Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Get-PSKoanSetting' { @@ -22,7 +38,7 @@ Describe 'Get-PSKoanSetting' { Context 'Settings file does not exist' { BeforeAll { - Mock 'Set-PSKoanSetting' -ParameterFilter { $Settings -is [hashtable] } + Mock 'Set-PSKoanSetting' -ParameterFilter { $Settings -is [hashtable] } -ModuleName 'PSKoans' $DefaultSettings = InModuleScope 'PSKoans' { $script:DefaultSettings } } ` @@ -34,7 +50,7 @@ Describe 'Get-PSKoanSetting' { } It 'calls Set-PSKoanSetting to set the default settings' { - Should -Invoke 'Set-PSKoanSetting' -Scope Context + Should -Invoke 'Set-PSKoanSetting' -Scope Context -ModuleName 'PSKoans' } } diff --git a/Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 b/Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 index 4763e628e..7b6f9b2d5 100644 --- a/Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 +++ b/Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Move-PSKoanLibrary' { @@ -9,9 +25,9 @@ Describe 'Move-PSKoanLibrary' { Select-Object -ExpandProperty FullName $TestPath = New-Item -ItemType Directory -Path 'TestDrive:/TestPath' | Join-Path -ChildPath 'Koans' - Mock 'Get-PSKoanLocation' { $OriginalPath } - Mock 'Set-PSKoanLocation' -ParameterFilter { $Path -eq $TestPath } - Mock 'Move-Item' -ParameterFilter { $Path -eq $OriginalPath } -MockWith { $Destination } + Mock 'Get-PSKoanLocation' { $OriginalPath } -ModuleName 'PSKoans' + Mock 'Set-PSKoanLocation' -ParameterFilter { $Path -eq $TestPath } -ModuleName 'PSKoans' + Mock 'Move-Item' -ParameterFilter { $Path -eq $OriginalPath } -MockWith { $Destination } -ModuleName 'PSKoans' } It 'should output the new location' { @@ -19,15 +35,15 @@ Describe 'Move-PSKoanLibrary' { } It 'should call Get-PSKoanLocation' { - Should -Invoke 'Get-PSKoanLocation' -Scope Context + Should -Invoke 'Get-PSKoanLocation' -Scope Context -ModuleName 'PSKoans' } It 'should call Move-Item' { - Should -Invoke 'Move-Item' -Scope Context + Should -Invoke 'Move-Item' -Scope Context -ModuleName 'PSKoans' } It 'should call Set-PSKoanLocation' { - Should -Invoke 'Set-PSKoanLocation' -Scope Context + Should -Invoke 'Set-PSKoanLocation' -Scope Context -ModuleName 'PSKoans' } } diff --git a/Tests/Functions/Public/Register-Advice.Tests.ps1 b/Tests/Functions/Public/Register-Advice.Tests.ps1 index 326a1931f..b077c52ab 100644 --- a/Tests/Functions/Public/Register-Advice.Tests.ps1 +++ b/Tests/Functions/Public/Register-Advice.Tests.ps1 @@ -1,13 +1,29 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe "Register-Advice" { Context "Profile Folder/File Missing" { BeforeAll { - Mock New-Item -Verifiable - Mock Test-Path { $false } -Verifiable - Mock Set-Content -ParameterFilter { $Value -eq "Show-Advice" } -Verifiable + Mock New-Item -Verifiable -ModuleName 'PSKoans' + Mock Test-Path { $false } -Verifiable -ModuleName 'PSKoans' + Mock Set-Content -ParameterFilter { $Value -eq "Show-Advice" } -Verifiable -ModuleName 'PSKoans' } It 'should create the $profile if it does not exist' { @@ -19,9 +35,9 @@ Describe "Register-Advice" { Context "Profile Already Exists" { BeforeAll { - Mock 'Test-Path' { $true } -Verifiable - Mock 'Select-String' { $false } -Verifiable - Mock 'Add-Content' -Verifiable + Mock 'Test-Path' { $true } -Verifiable -ModuleName 'PSKoans' + Mock 'Select-String' { $false } -Verifiable -ModuleName 'PSKoans' + Mock 'Add-Content' -Verifiable -ModuleName 'PSKoans' } It "adds content to the profile if it already exists (Get|Set)-Advice" { @@ -33,10 +49,11 @@ Describe "Register-Advice" { Context "Parameter Validation" { BeforeAll { - Mock Test-Path { $false } -ParameterFilter { $Path -eq $ProfileFolder } - Mock New-Item - Mock Test-Path { $false } -ParameterFilter { $Path -eq $ProfilePath } - Mock Set-Content -ParameterFilter { $Value -eq "Show-Advice" } + Mock Test-Path { $false } -ModuleName 'PSKoans' + Mock New-Item -ModuleName 'PSKoans' + Mock Select-String { $false } -ModuleName 'PSKoans' + Mock Add-Content -ModuleName 'PSKoans' + Mock Set-Content -ParameterFilter { $Value -eq "Show-Advice" } -ModuleName 'PSKoans' } It "throws if an invalid value is supplied for -TargetProfile" { diff --git a/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 b/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 index 885ab87c9..8ba66ab57 100644 --- a/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 +++ b/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe Reset-PSKoan { @@ -7,14 +23,23 @@ Describe Reset-PSKoan { Confirm = $false } - Mock 'Get-PSKoanLocation' { - Join-Path -Path $TestDrive -ChildPath 'PSKoans' + $koanLocation = Join-Path -Path $TestDrive -ChildPath 'PSKoans' + $moduleKoanPath = Join-Path -Path $TestDrive -ChildPath 'Module\Group\AboutSomething.Koans.ps1' + + Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } + + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' -MockWith { + [PSCustomObject]@{ + Topic = 'AboutSomething' + Path = $moduleKoanPath + RelativePath = 'Group\AboutSomething.Koans.ps1' + } } - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -MockWith { + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' -MockWith { [PSCustomObject]@{ Topic = 'AboutSomething' - Path = Join-Path -Path $TestDrive -ChildPath 'Module\Group\AboutSomething.Koans.ps1' + Path = $userFilePath RelativePath = 'Group\AboutSomething.Koans.ps1' } } @@ -22,9 +47,9 @@ Describe Reset-PSKoan { New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'Module\Group') -ItemType Directory New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'PSKoans\Group') -ItemType Directory - $userFilePath = Get-PSKoanLocation | Join-Path -ChildPath 'Group\AboutSomething.Koans.ps1' + $userFilePath = Join-Path -Path $koanLocation -ChildPath 'Group\AboutSomething.Koans.ps1' - Set-Content -Path (Get-PSKoan -Scope Module).Path, $userFilePath -Value @' + Set-Content -Path $moduleKoanPath, $userFilePath -Value @' using module PSKoans [Koan(Position = 1)] param ( ) @@ -56,43 +81,45 @@ Describe Reset-PSKoan { Context 'User file exists, It block exists' { BeforeAll { - Mock 'Set-Content' - Mock 'Copy-Item' + Mock 'Set-Content' -ModuleName 'PSKoans' + Mock 'Copy-Item' -ModuleName 'PSKoans' } It 'updates an existing user file when -Name is supplied' { Reset-PSKoan -Name 'existing content' @defaultParams - Should -Invoke 'Set-Content' -Times 1 - Should -Invoke 'Copy-Item' -Times 0 + Should -Invoke 'Set-Content' -Times 1 -ModuleName 'PSKoans' + Should -Invoke 'Copy-Item' -Times 0 -ModuleName 'PSKoans' } It 'updates an existing user file when -Context is supplied' { Reset-PSKoan -Context 'first' @defaultParams - Should -Invoke 'Set-Content' -Times 1 -Exactly - Should -Invoke 'Copy-Item' -Times 0 + Should -Invoke 'Set-Content' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Copy-Item' -Times 0 -ModuleName 'PSKoans' } It 'updates an existing user file when -Name and -Context are supplied' { Reset-PSKoan -Name 'nested reset content' -Context 'first' @defaultParams - Should -Invoke 'Set-Content' -Times 1 -Exactly - Should -Invoke 'Copy-Item' -Times 0 + Should -Invoke 'Set-Content' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Copy-Item' -Times 0 -ModuleName 'PSKoans' } It 'copies a koan file from the module when -Name and -Context are not supplied' { Reset-PSKoan @defaultParams - Should -Invoke 'Set-Content' -Times 0 - Should -Invoke 'Copy-Item' -Times 1 -Exactly + Should -Invoke 'Set-Content' -Times 0 -ModuleName 'PSKoans' + Should -Invoke 'Copy-Item' -Times 1 -Exactly -ModuleName 'PSKoans' } } Context 'User file exists, It block does not exist' { It 'writes a non-terminating error when the user file does not include the specified Koan' { - Mock 'Get-KoanIt' -ParameterFilter { $Path -match 'PSKoans' } -Module 'PSKoans' + $realGetKoanIt = InModuleScope 'PSKoans' { Get-Item -Path 'Function:\Get-KoanIt' } + Mock 'Get-KoanIt' -ModuleName 'PSKoans' -MockWith { & $realGetKoanIt @args } + Mock 'Get-KoanIt' -ParameterFilter { $Path -match 'PSKoans' } -ModuleName 'PSKoans' { Reset-PSKoan -Topic AboutSomething -Name 'existing content' -ErrorAction Stop @defaultParams } | Should -Throw -ErrorId 'PSKoans.UserItNotFound,Reset-PSKoan' @@ -104,8 +131,8 @@ Describe Reset-PSKoan { BeforeAll { New-Item "$TestDrive/DoesNotExist.Koans.ps1" -ItemType File > $null - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -Verifiable - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -Verifiable -MockWith { + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -Verifiable -ModuleName 'PSKoans' + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -Verifiable -ModuleName 'PSKoans' -MockWith { [PSCustomObject]@{ Topic = $Topic Module = '_powershell' @@ -116,28 +143,29 @@ Describe Reset-PSKoan { } } - Mock 'Update-PSKoan' + Mock 'Update-PSKoan' -ModuleName 'PSKoans' } It 'calls Update-PSKoan when the topic does not exist in the user location' { Reset-PSKoan -Topic DoesNotExist -ErrorAction Stop @defaultParams Should -InvokeVerifiable - Should -Invoke Update-PSKoan -Times 1 -Exactly + Should -Invoke Update-PSKoan -Times 1 -Exactly -ModuleName 'PSKoans' } } Context 'Module file does not exist' { BeforeAll { - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' } It 'throws a terminating error when no topics are found in the module' { { Reset-PSKoan -Topic DoesNotExist @defaultParams } | Should -Throw -ErrorId 'PSKoans.ModuleTopicNotFound,Reset-PSKoan' - Should -Invoke 'Get-PSKoan' -Times 1 -Exactly + Should -Invoke 'Get-PSKoan' -Times 1 -Exactly -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' } } diff --git a/Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 b/Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 index cac34f907..88d54c365 100644 --- a/Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 +++ b/Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 @@ -1,9 +1,25 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Set-PSKoanLocation' { BeforeAll { - Mock 'Set-PSKoanSetting' -ParameterFilter { $Name -eq 'KoanLocation' } + Mock 'Set-PSKoanSetting' -ParameterFilter { $Name -eq 'KoanLocation' } -ModuleName 'PSKoans' } It 'outputs no data by default' { @@ -11,7 +27,7 @@ Describe 'Set-PSKoanLocation' { } It 'sets the KoanLocation setting' { - Should -Invoke 'Set-PSKoanSetting' -Scope Describe + Should -Invoke 'Set-PSKoanSetting' -Scope Describe -ModuleName 'PSKoans' } It 'returns the input -Path value back to the pipeline with -PassThru' { diff --git a/Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 b/Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 index 5feec692f..063bb4cd6 100644 --- a/Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 +++ b/Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Set-PSKoanSetting' { diff --git a/Tests/Functions/Public/Show-Advice.Tests.ps1 b/Tests/Functions/Public/Show-Advice.Tests.ps1 index e91fa726a..6724cc15b 100644 --- a/Tests/Functions/Public/Show-Advice.Tests.ps1 +++ b/Tests/Functions/Public/Show-Advice.Tests.ps1 @@ -1,4 +1,20 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe "Show-Advice" { @@ -50,8 +66,8 @@ Describe "Show-Advice" { BeforeAll { $GetContentResult = [string]::Empty - Mock Get-Content -MockWith { $GetContentResult } -Verifiable - Mock Get-ChildItem -MockWith { [PSCustomObject]@{ PSPath = "DummyPath" } } -Verifiable + Mock Get-Content -MockWith { $GetContentResult } -Verifiable -ModuleName 'PSKoans' + Mock Get-ChildItem -MockWith { [PSCustomObject]@{ PSPath = "DummyPath" } } -Verifiable -ModuleName 'PSKoans' } It "should throw an error if the requested file's format is not correct" -TestCases @( diff --git a/Tests/Functions/Public/Show-Karma.Tests.ps1 b/Tests/Functions/Public/Show-Karma.Tests.ps1 index f0bd6fb8e..d75a6c4b7 100644 --- a/Tests/Functions/Public/Show-Karma.Tests.ps1 +++ b/Tests/Functions/Public/Show-Karma.Tests.ps1 @@ -1,11 +1,26 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Show-Karma' { BeforeAll { - Mock 'Get-PSKoanLocation' { - "$TestDrive/Koans" - } + $koanLocation = "$TestDrive/Koans" + Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } $EditorSetting = Get-PSKoanSetting -Name Editor @@ -19,8 +34,8 @@ Describe 'Show-Karma' { Context 'Default Behaviour' { BeforeAll { - Mock 'Out-Host' - Mock 'Get-Karma' { + Mock 'Out-Host' -ModuleName 'PSKoans' + Mock 'Get-Karma' -ModuleName 'PSKoans' { [PSCustomObject]@{ PSTypeName = 'PSKoans.Result' Meditation = 'TestMeditation' @@ -44,19 +59,19 @@ Describe 'Show-Karma' { } It 'should write the formatted output to host' { - Should -Invoke 'Out-Host' -Scope Context + Should -Invoke 'Out-Host' -Scope Context -ModuleName 'PSKoans' } It 'should call Get-Karma to examine the koans' { - Should -Invoke 'Get-Karma' -Scope Context + Should -Invoke 'Get-Karma' -Scope Context -ModuleName 'PSKoans' } } Context 'With All Koans Completed' { BeforeAll { - Mock 'Out-Host' -Verifiable - Mock 'Get-Karma' -Verifiable { + Mock 'Out-Host' -Verifiable -ModuleName 'PSKoans' + Mock 'Get-Karma' -Verifiable -ModuleName 'PSKoans' { [PSCustomObject]@{ PSTypeName = 'PSKoans.CompleteResult' KoansPassed = 10 @@ -76,9 +91,9 @@ Describe 'Show-Karma' { Context 'With -ClearScreen Switch' { BeforeAll { - Mock 'Clear-Host' - Mock 'Out-Host' - Mock 'Get-Karma' { + Mock 'Clear-Host' -ModuleName 'PSKoans' + Mock 'Out-Host' -ModuleName 'PSKoans' + Mock 'Get-Karma' -ModuleName 'PSKoans' { [PSCustomObject]@{ PSTypeName = 'PSKoans.Result' Meditation = 'TestMeditation' @@ -102,27 +117,27 @@ Describe 'Show-Karma' { } It 'should clear the screen' { - Should -Invoke 'Clear-Host' -Scope Context -Times 1 -Exactly + Should -Invoke 'Clear-Host' -Scope Context -Times 1 -Exactly -ModuleName 'PSKoans' } It 'should display the rendered output' { - Should -Invoke 'Out-Host' -Scope Context + Should -Invoke 'Out-Host' -Scope Context -ModuleName 'PSKoans' } It 'should use Get-Karma to retrieve koan results' { - Should -Invoke 'Get-Karma' -Scope Context -Times 1 -Exactly + Should -Invoke 'Get-Karma' -Scope Context -Times 1 -Exactly -ModuleName 'PSKoans' } } Context 'With Nonexistent Koans Folder / No Koans Found' { BeforeAll { - Mock 'Write-Host' - Mock 'Get-PSKoan' - Mock 'Update-PSKoan' { throw 'Prevent recursion' } - Mock 'Write-Warning' - Mock 'Test-Path' { $false } - Mock 'Invoke-Item' + Mock 'Write-Host' -ModuleName 'PSKoans' + Mock 'Get-PSKoan' -ModuleName 'PSKoans' + Mock 'Update-PSKoan' { throw 'Prevent recursion' } -ModuleName 'PSKoans' + Mock 'Write-Warning' -ModuleName 'PSKoans' + Mock 'Test-Path' { $false } -ModuleName 'PSKoans' + Mock 'Invoke-Item' -ModuleName 'PSKoans' Mock 'Measure-Koan' -ModuleName 'PSKoans' } @@ -135,7 +150,7 @@ Describe 'Show-Karma' { } It 'should display a warning before initiating a reset' { - Should -Invoke 'Write-Warning' -Scope Context -Times 1 -Exactly + Should -Invoke 'Write-Warning' -Scope Context -Times 1 -Exactly -ModuleName 'PSKoans' } It 'throws an error if a Topic is specified that matches nothing' { @@ -145,35 +160,35 @@ Describe 'Show-Karma' { It 'should create PSKoans directory with -Library' { { Show-Karma -Library } | Should -Throw -ExpectedMessage 'Prevent recursion' - Should -Invoke 'Test-Path' - Should -Invoke 'Update-PSKoan' -Times 1 -Exactly + Should -Invoke 'Test-Path' -ModuleName 'PSKoans' + Should -Invoke 'Update-PSKoan' -Times 1 -Exactly -ModuleName 'PSKoans' } It 'should call Get-PSKoan to retrieve the correct file -Contemplate' { { Show-Karma -Contemplate } | Should -Throw -ExpectedMessage 'Prevent recursion' - Should -Invoke 'Get-PSKoan' -Times 1 -Exactly - Should -Invoke 'Update-PSKoan' -Times 1 -Exactly + Should -Invoke 'Get-PSKoan' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Update-PSKoan' -Times 1 -Exactly -ModuleName 'PSKoans' } } Context 'With -ListTopics Parameter' { BeforeAll { - Mock 'Get-PSKoan' + Mock 'Get-PSKoan' -ModuleName 'PSKoans' } It 'should list all the koan topics' { Show-Karma -ListTopics - Should -Invoke 'Get-PSKoan' -Times 1 -Exactly + Should -Invoke 'Get-PSKoan' -Times 1 -Exactly -ModuleName 'PSKoans' } } Context 'With -Topic Parameter' { BeforeAll { - Mock 'Out-Host' -Verifiable - Mock 'Get-Karma' -ParameterFilter { $Topic -eq 'TestTopic' } -Verifiable -MockWith { + Mock 'Out-Host' -Verifiable -ModuleName 'PSKoans' + Mock 'Get-Karma' -ParameterFilter { $Topic -eq 'TestTopic' } -Verifiable -ModuleName 'PSKoans' -MockWith { [PSCustomObject]@{ PSTypeName = 'PSKoans.Result' Meditation = 'TestMeditation' @@ -202,9 +217,9 @@ Describe 'Show-Karma' { Context 'With All Koans in a Single Topic Completed' { BeforeAll { - Mock 'Format-Custom' -Verifiable { $null } - Mock 'Out-Host' -Verifiable - Mock 'Get-Karma' -Verifiable { + Mock 'Format-Custom' -Verifiable -ModuleName 'PSKoans' { $null } + Mock 'Out-Host' -Verifiable -ModuleName 'PSKoans' + Mock 'Get-Karma' -Verifiable -ModuleName 'PSKoans' { [PSCustomObject]@{ PSTypeName = 'PSKoans.CompleteResult' KoansPassed = 10 @@ -226,14 +241,14 @@ Describe 'Show-Karma' { BeforeAll { $TestFile = New-TemporaryFile - Mock 'Invoke-Item' { $Path } - Mock 'Get-Command' { $true } -ParameterFilter { $Name -ne "missing_editor" } - Mock 'Get-Command' { $false } -ParameterFilter { $Name -eq "missing_editor" } - Mock 'Start-Process' { + Mock 'Invoke-Item' { $Path } -ModuleName 'PSKoans' + Mock 'Get-Command' { $true } -ParameterFilter { $Name -ne "missing_editor" } -ModuleName 'PSKoans' + Mock 'Get-Command' { $false } -ParameterFilter { $Name -eq "missing_editor" } -ModuleName 'PSKoans' + Mock 'Start-Process' -ModuleName 'PSKoans' { @{ Editor = $FilePath; Arguments = $ArgumentList; NoNewWindow = $NoNewWindow } } - Mock 'Get-Karma' { + Mock 'Get-Karma' -ModuleName 'PSKoans' { $currentTopic = @{ Name = 'TestTopic' Completed = 0 @@ -258,7 +273,7 @@ Describe 'Show-Karma' { } } - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } { + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' { [PSCustomObject]@{ Path = $TestFile.FullName } } } @@ -281,8 +296,8 @@ Describe 'Show-Karma' { $Path = ($Result.Arguments[1] -split '(?<="):')[0] -replace '"' $Path | Should -BeExactly (Resolve-Path -Path $Path).Path - Should -Invoke 'Get-Command' -Times 1 -Exactly - Should -Invoke 'Start-Process' -Times 1 -Exactly + Should -Invoke 'Get-Command' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Start-Process' -Times 1 -Exactly -ModuleName 'PSKoans' InModuleScope 'PSKoans' { $script:CurrentTopic } | Should -BeNullOrEmpty } @@ -306,10 +321,10 @@ Describe 'Show-Karma' { $Path = ($Result.Arguments[1] -split '(?<="):')[0] -replace '"' $Path | Should -BeExactly (Resolve-Path -Path $Path).Path - Should -Invoke 'Get-Command' -Times 1 -Exactly - Should -Invoke 'Start-Process' -Times 1 -Exactly - Should -Invoke 'Get-Karma' -ParameterFilter { $Module -eq $ModuleName } - Should -Invoke 'Get-PSKoan' -ParameterFilter { $IncludeModule -eq $ModuleName } + Should -Invoke 'Get-Command' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Start-Process' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Get-Karma' -ParameterFilter { $Module -eq $ModuleName } -ModuleName 'PSKoans' + Should -Invoke 'Get-PSKoan' -ParameterFilter { $IncludeModule -eq $ModuleName } -ModuleName 'PSKoans' InModuleScope 'PSKoans' { $script:CurrentTopic } | Should -BeNullOrEmpty } @@ -320,8 +335,8 @@ Describe 'Show-Karma' { $Result = Show-Karma -Contemplate -Topic TestTopic $Result.Arguments[1] | Should -MatchExactly ([regex]::Escape($TestFile.FullName)) - Should -Invoke 'Get-Command' -Times 1 -Exactly - Should -Invoke 'Start-Process' -Times 1 -Exactly + Should -Invoke 'Get-Command' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Start-Process' -Times 1 -Exactly -ModuleName 'PSKoans' InModuleScope 'PSKoans' { $script:CurrentTopic } | Should -BeNullOrEmpty } @@ -337,8 +352,8 @@ Describe 'Show-Karma' { $Path = $Result.Arguments -replace '"' $Path | Should -BeExactly (Resolve-Path -Path $Path).Path - Should -Invoke 'Get-Command' -Times 1 -Exactly - Should -Invoke 'Start-Process' -Times 1 -Exactly + Should -Invoke 'Get-Command' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Start-Process' -Times 1 -Exactly -ModuleName 'PSKoans' InModuleScope 'PSKoans' { $script:CurrentTopic } | Should -BeNullOrEmpty } @@ -348,8 +363,8 @@ Describe 'Show-Karma' { Show-Karma -Contemplate | Should -BeExactly $TestFile.FullName - Should -Invoke 'Get-Command' -Times 1 -Exactly -ParameterFilter { $Name -eq "missing_editor" } - Should -Invoke 'Invoke-Item' -Times 1 -Exactly + Should -Invoke 'Get-Command' -Times 1 -Exactly -ParameterFilter { $Name -eq "missing_editor" } -ModuleName 'PSKoans' + Should -Invoke 'Invoke-Item' -Times 1 -Exactly -ModuleName 'PSKoans' InModuleScope 'PSKoans' { $script:CurrentTopic } | Should -BeNullOrEmpty } @@ -358,12 +373,12 @@ Describe 'Show-Karma' { Context 'With -Library Switch' { BeforeAll { - Mock 'Get-Command' { $true } -ParameterFilter { $Name -ne "missing_editor" } - Mock 'Get-Command' { $false } -ParameterFilter { $Name -eq "missing_editor" } - Mock 'Start-Process' { + Mock 'Get-Command' { $true } -ParameterFilter { $Name -ne "missing_editor" } -ModuleName 'PSKoans' + Mock 'Get-Command' { $false } -ParameterFilter { $Name -eq "missing_editor" } -ModuleName 'PSKoans' + Mock 'Start-Process' -ModuleName 'PSKoans' { @{ Editor = $FilePath; Arguments = $ArgumentList } } - Mock 'Invoke-Item' { $Path } + Mock 'Invoke-Item' { $Path } -ModuleName 'PSKoans' } It 'invokes VS Code with "code" set as Editor with proper arguments' { @@ -376,8 +391,8 @@ Describe 'Show-Karma' { $Path = $Result.Arguments -replace '"' $Path | Should -BeExactly (Resolve-Path -Path $Path).Path - Should -Invoke 'Get-Command' -Times 1 -Exactly - Should -Invoke 'Start-Process' -Times 1 -Exactly + Should -Invoke 'Get-Command' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Start-Process' -Times 1 -Exactly -ModuleName 'PSKoans' } It 'invokes the set editor with unknown editor chosen' { @@ -390,17 +405,17 @@ Describe 'Show-Karma' { $Path = $Result.Arguments -replace '"' $Path | Should -BeExactly (Resolve-Path -Path $Path).Path - Should -Invoke 'Get-Command' -Times 1 -Exactly - Should -Invoke 'Start-Process' -Times 1 -Exactly + Should -Invoke 'Get-Command' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Start-Process' -Times 1 -Exactly -ModuleName 'PSKoans' } It 'opens the file directly when selected editor is unavailable' { Set-PSKoanSetting -name Editor -Value "missing_editor" - Show-Karma -Library | Should -BeExactly (Get-PSKoanLocation) + Show-Karma -Library | Should -BeExactly $koanLocation - Should -Invoke 'Get-Command' -Times 1 -Exactly -ParameterFilter { $Name -eq "missing_editor" } - Should -Invoke 'Invoke-Item' -Times 1 -Exactly + Should -Invoke 'Get-Command' -Times 1 -Exactly -ParameterFilter { $Name -eq "missing_editor" } -ModuleName 'PSKoans' + Should -Invoke 'Invoke-Item' -Times 1 -Exactly -ModuleName 'PSKoans' } } } diff --git a/Tests/Functions/Public/Update-PSKoan.Tests.ps1 b/Tests/Functions/Public/Update-PSKoan.Tests.ps1 index d86cf7f29..610a895de 100644 --- a/Tests/Functions/Public/Update-PSKoan.Tests.ps1 +++ b/Tests/Functions/Public/Update-PSKoan.Tests.ps1 @@ -1,17 +1,33 @@ -#Requires -Modules PSKoans +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} Describe 'Update-PSKoan' { Context 'Mocked Commands' { BeforeAll { - Mock 'Remove-Item' - Mock 'Copy-Item' - Mock 'New-Item' - Mock 'Move-Item' + Mock 'Remove-Item' -ModuleName 'PSKoans' + Mock 'Copy-Item' -ModuleName 'PSKoans' + Mock 'New-Item' -ModuleName 'PSKoans' + Mock 'Move-Item' -ModuleName 'PSKoans' Mock 'Update-PSKoanFile' -ModuleName 'PSKoans' - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -MockWith { + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' -MockWith { [PSCustomObject]@{ Topic = 'Missing' Path = 'Module\Group\AboutSomethingMissing.Koans.ps1' @@ -26,7 +42,7 @@ Describe 'Update-PSKoan' { } } - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -MockWith { + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' -MockWith { [PSCustomObject]@{ Topic = 'IncorrectPath' Path = 'Module\RetiredGroup\AboutSomethingIncorrectPath.Koans.ps1' @@ -47,15 +63,15 @@ Describe 'Update-PSKoan' { } It 'should copy missing topic files' { - Should -Invoke 'Copy-Item' -Times 1 -Scope Context + Should -Invoke 'Copy-Item' -Times 1 -Scope Context -ModuleName 'PSKoans' } It 'should move incorrectly placed topics' { - Should -Invoke 'Remove-Item' -Times 1 -Scope Context + Should -Invoke 'Remove-Item' -Times 1 -Scope Context -ModuleName 'PSKoans' } It 'should remove discarded topics' { - Should -Invoke 'Remove-Item' -Times 1 -Scope Context + Should -Invoke 'Remove-Item' -Times 1 -Scope Context -ModuleName 'PSKoans' } It 'should update topics which exist in module and koan path' { @@ -66,14 +82,13 @@ Describe 'Update-PSKoan' { Context 'Practical Tests with TestDrive' { BeforeAll { - Mock 'Get-PSKoanLocation' { - Join-Path -Path $TestDrive -ChildPath 'PSKoans' - } + $koanLocation = Join-Path -Path $TestDrive -ChildPath 'PSKoans' + Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } - New-Item -Path (Get-PSKoanLocation) -ItemType Directory + New-Item -Path $koanLocation -ItemType Directory Update-PSKoan -Confirm:$false - $file = Get-ChildItem -Path (Get-PSKoanLocation) -Filter *.koans.ps1 -File -Recurse | + $file = Get-ChildItem -Path $koanLocation -Filter *.koans.ps1 -File -Recurse | Select-Object -First 1 } diff --git a/Tests/KoanValidation.Tests.ps1 b/Tests/KoanValidation.Tests.ps1 index ac6b8e6c3..5f0f26fcf 100644 --- a/Tests/KoanValidation.Tests.ps1 +++ b/Tests/KoanValidation.Tests.ps1 @@ -1,8 +1,24 @@ -#Requires -Modules PSKoans - using namespace System.Management.Automation.Language using namespace System.Collections.Generic +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} + Describe 'Static Analysis: Koan Topics' { Context 'Individual Topics' { diff --git a/Tests/ModuleHelp.Tests.ps1 b/Tests/ModuleHelp.Tests.ps1 index 18141f0f4..03da77101 100644 --- a/Tests/ModuleHelp.Tests.ps1 +++ b/Tests/ModuleHelp.Tests.ps1 @@ -1,20 +1,27 @@ -#region Discovery +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } -$ModuleName = 'PSKoans' - -#endregion Discovery - -BeforeAll { - $ModuleName = 'PSKoans' - Import-Module $ModuleName +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop } +$ModuleName = 'PSKoans' + Describe "$ModuleName Sanity Tests - Help Content" -Tags 'Module' { #region Discovery - # The module will need to be imported during Discovery since we're using it to generate test cases / Context blocks - Import-Module $ModuleName $ShouldProcessParameters = 'WhatIf', 'Confirm' @@ -72,16 +79,20 @@ Describe "$ModuleName Sanity Tests - Help Content" -Tags 'Module' { @($Parameters).Count | Should -Be $Ast.Body.ParamBlock.Parameters.Count -Because 'the number of parameters in the help should match the number in the function script' } - It "has a description for $Command parameter -" -TestCases $Parameters -Skip:(-not $Parameters) { - $Description | Should -Not -BeNullOrEmpty -Because "parameter $Name should have a description" + if ($Parameters) { + It "has a description for $Command parameter -" -TestCases $Parameters { + $Description | Should -Not -BeNullOrEmpty -Because "parameter $Name should have a description" + } } It "has at least one usage example for $Command" -TestCases $Help { $Help.Examples.Example.Code.Count | Should -BeGreaterOrEqual 1 } - It "lists a description for $Command example: " -TestCases $Examples { - $Example.Remarks | Should -Not -BeNullOrEmpty -Because "example $($Example.Title) should have a description!" + if ($Examples) { + It "lists a description for $Command example: <Title>" -TestCases $Examples { + $Example.Remarks | Should -Not -BeNullOrEmpty -Because "example $($Example.Title) should have a description!" + } } } } diff --git a/Tests/ModuleValidation.Tests.ps1 b/Tests/ModuleValidation.Tests.ps1 index b13f7c992..ec1bc7228 100644 --- a/Tests/ModuleValidation.Tests.ps1 +++ b/Tests/ModuleValidation.Tests.ps1 @@ -1,3 +1,21 @@ +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + .\build.ps1 -Task Build + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} + Describe 'Static Analysis: Module & Repository Files' { #region Discovery diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 000000000..270ed073a --- /dev/null +++ b/build.ps1 @@ -0,0 +1,67 @@ +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSReviewUnusedParameter', + 'Command', + Justification = 'false positive' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSReviewUnusedParameter', + 'Parameter', + Justification = 'false positive' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSReviewUnusedParameter', + 'CommandAst', + Justification = 'false positive' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSReviewUnusedParameter', + 'FakeBoundParams', + Justification = 'false positive' +)] +[CmdletBinding(DefaultParameterSetName = 'task')] +param( + [parameter(ParameterSetName = 'task', Position = 0)] + [ArgumentCompleter( { + param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams) + try { + Get-PSakeScriptTasks -BuildFile './psakeFile.ps1' -ErrorAction 'Stop' | + Where-Object { $_.Name -like "$WordToComplete*" } | + Select-Object -ExpandProperty 'Name' + } + catch { + @() + } + })] + [string[]]$Task = 'default', + [switch]$Bootstrap, + [parameter(ParameterSetName = 'Help')] + [switch]$Help +) + +$ErrorActionPreference = 'Stop' +$psakeFile = './psakeFile.ps1' + +if ($Bootstrap) { + if (-not (Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue)) { + Install-PackageProvider -Name NuGet -Force -Scope CurrentUser | Out-Null + } + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted + if (-not (Get-Module -Name PSDepend -ListAvailable)) { + Install-Module -Name PSDepend -Repository PSGallery -Scope CurrentUser -Force -RequiredVersion '0.3.8' + } + Import-Module -Name PSDepend -Verbose:$false + Invoke-PSDepend -Path './requirements.psd1' -Install -Import -Force -WarningAction SilentlyContinue +} +else { + Invoke-PSDepend -Path './requirements.psd1' -Import -Force -WarningAction SilentlyContinue +} + +if ($PSCmdlet.ParameterSetName -eq 'Help') { + Get-PSakeScriptTasks -BuildFile $psakeFile | + Format-Table -Property Name, Description, Alias, DependsOn +} +else { + Set-BuildEnvironment -Force + Invoke-Psake -BuildFile $psakeFile -TaskList $Task -NoLogo + exit ([int](-not $psake.build_success)) +} diff --git a/psakeFile.ps1 b/psakeFile.ps1 new file mode 100644 index 000000000..6c712288c --- /dev/null +++ b/psakeFile.ps1 @@ -0,0 +1,46 @@ +Properties { + # PSKoans stages files without compiling to a single PSM1 + $PSBPreference.Build.CompileModule = $false + + # Help generation + $PSBPreference.Help.DefaultLocale = 'en-US' + + # Test configuration -- the module must be imported from the staged output before + # Pester runs since the test suite expects `PSKoans` to already be loaded/resolvable + $PSBPreference.Test.RootDir = Join-Path $ENV:BHProjectPath 'Tests' + $PSBPreference.Test.ImportModule = $true + $PSBPreference.Test.OutputFile = 'out/testResults.xml' + $PSBPreference.Test.OutputFormat = 'JUnitXml' + $PSBPreference.Test.ScriptAnalysis.Enabled = $true + $PSBPreference.Test.ScriptAnalysis.FailBuildOnSeverityLevel = 'Error' + $PSBPreference.Test.CodeCoverage.Enabled = $false + + $PSBPreference.Publish.PSRepositoryApiKey = $env:PSGALLERY_API_KEY +} + +# The module manifest's FormatsToProcess entry (PSKoans.format.ps1xml) is generated +# from ./formatting via EZOut and is gitignored -- it must exist before the module +# can be imported at all, so generate it ahead of staging. +Task GenerateFormatData -Depends Clean { + & (Join-Path $PSBPreference.General.ProjectRoot 'PSKoans.ezformat.ps1') +} -Description 'Generates PSKoans.format.ps1xml from ./formatting' + +$PSBStageFilesDependency = @('Clean', 'GenerateFormatData') +$PSBBuildDependency = @('StageFiles') + +Task Default -Depends Test + +# PowerShellBuild adds the following tasks: +# - Init +# - Clean +# - StageFiles +# - Build +# - Analyze +# - Pester +# - Test +# - BuildHelp +# - GenerateMarkdown +# - GenerateMAML +# - GenerateUpdatableHelp +# - Publish +Task Test -FromModule PowerShellBuild -MinimumVersion '0.7.3' diff --git a/requirements.psd1 b/requirements.psd1 new file mode 100644 index 000000000..e8741d4e5 --- /dev/null +++ b/requirements.psd1 @@ -0,0 +1,25 @@ +@{ + PSDependOptions = @{ + Target = 'CurrentUser' + } + 'psake' = @{ + Version = '4.9.1' + } + 'PowerShellBuild' = @{ + Version = '0.7.3' + } + 'Pester' = @{ + Parameters = @{ + SkipPublisherCheck = $true + } + } + 'PSScriptAnalyzer' = @{ + Version = '1.19.1' + } + 'BuildHelpers' = @{ + Version = '2.0.16' + } + 'EZOut' = @{ + Version = '2.0.6' + } +} From 448282bb056794950aba596559778beebf962b2f Mon Sep 17 00:00:00 2001 From: Gilbert Sanchez <me@gilbertsanchez.com> Date: Wed, 16 Sep 2026 23:08:47 -0700 Subject: [PATCH 2/4] docs: restore comment-based help for public functions Copies the existing PlatyPS-generated docs/*.md content back into comment-based help blocks for all 13 exported functions, matching the style already used throughout PSKoans/Private/*.ps1 (help block as the first statement inside the function body). Verified every function's declared parameter set still matches what's documented in docs/*.md (no drift), so this is a straight port, not a rewrite. Fixes the ~90 ModuleHelp.Tests.ps1 failures from PR #493 by supplying Synopsis, Description, per-parameter descriptions, examples with remarks, and an Author note for each function. Invoke-psake Test: 739 passed / 10 failed (down from 631/100). The 10 remaining failures are all the pre-existing Invoke-Koan -Script/Pester 5 incompatibility already called out in #493 -- unrelated to this change. --- PSKoans/Public/Get-Blank.ps1 | 39 ++++++++++ PSKoans/Public/Get-Karma.ps1 | 41 ++++++++++ PSKoans/Public/Get-PSKoan.ps1 | 66 +++++++++++++++++ PSKoans/Public/Get-PSKoanLocation.ps1 | 21 ++++++ PSKoans/Public/Get-PSKoanSetting.ps1 | 34 +++++++++ PSKoans/Public/Move-PSKoanLibrary.ps1 | 29 ++++++++ PSKoans/Public/Register-Advice.ps1 | 25 +++++++ PSKoans/Public/Reset-PSKoan.ps1 | 74 +++++++++++++++++++ PSKoans/Public/Set-PSKoanLocation.ps1 | 37 ++++++++++ PSKoans/Public/Set-PSKoanSetting.ps1 | 40 ++++++++++ PSKoans/Public/Show-Advice.ps1 | 25 +++++++ PSKoans/Public/Show-Karma.ps1 | 72 ++++++++++++++++++ PSKoans/Public/Update-PSKoan.ps1 | 49 ++++++++++++ Tests/Functions/Private/Invoke-Koan.Tests.ps1 | 56 ++++++-------- 14 files changed, 575 insertions(+), 33 deletions(-) diff --git a/PSKoans/Public/Get-Blank.ps1 b/PSKoans/Public/Get-Blank.ps1 index 2ddc46a5f..7dfba8e9f 100644 --- a/PSKoans/Public/Get-Blank.ps1 +++ b/PSKoans/Public/Get-Blank.ps1 @@ -1,4 +1,43 @@ function Get-Blank { + <# + .SYNOPSIS + Gets a blank item that does not equal anything. + + .DESCRIPTION + Get-Blank returns an object of type [Blank] as defined in the PSKoans module. + This object is not equivalent to any other type of object, including itself, when compared + with a standard `-eq` comparison. + + The only exception, which is unavoidable, is that it is considered equal to $true when + $true is on the left-hand side of the comparison. This kind of comparison may sometimes + need to be carefully avoided when framing a koan assertion. + + For instance,an assertion such as `____ | Should -BeTrue` WILL pass, although it should not. + + .PARAMETER |PipeInput + Used to capture the input in a pipeline context, to avoid erroring out in those contexts. + This parameter is not intended to be used directly, and captures all pipeline input. + + .PARAMETER |ParameterInput + Used to capture parameter names and arguments when used as a substitute for any other cmdlet. + This parameter is not intended to be used directly, and collects all argument names and values. + + .EXAMPLE + Get-Blank + + Returns a blank object. + + .EXAMPLE + __ + + Returns a blank object. + + .NOTES + Author: Joel Sallow (@vexx32) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Get-Blank.md')] [OutputType('Blank')] [Alias('__', '____', 'FILL_ME_IN')] diff --git a/PSKoans/Public/Get-Karma.ps1 b/PSKoans/Public/Get-Karma.ps1 index f24ddc121..5c02fa9e5 100644 --- a/PSKoans/Public/Get-Karma.ps1 +++ b/PSKoans/Public/Get-Karma.ps1 @@ -1,4 +1,45 @@ function Get-Karma { + <# + .SYNOPSIS + Retrieves information about your progress in PSKoans. + + .DESCRIPTION + Get-Karma executes Pester against the koans and outputs a short report on your current progress. + + .PARAMETER IncludeModule + Get Karma for the default PowerShell Koans as well as Koans for the specified module. + Wildcards are supported. + + .PARAMETER List + Output a complete list of available koan topics. + + .PARAMETER Module + Get Karma for the specified module only. + Wildcards are supported. + + .PARAMETER Topic + Execute koans only from the selected Topic(s). + Wildcard patterns are permitted. + + .EXAMPLE + Get-Karma + + Outputs a hashtable containing information about your progress. + + .EXAMPLE + Get-Karma -List + + Outputs a list of koan topics, including both the user file location and the module file location. + + .NOTES + Author: Joel Sallow (@vexx32) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Get-Karma.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(DefaultParameterSetName = 'Default', HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Get-Karma.md')] [OutputType('PSKoans.Result', 'PSKoans.CompleteResult')] diff --git a/PSKoans/Public/Get-PSKoan.ps1 b/PSKoans/Public/Get-PSKoan.ps1 index 49645d3d3..f763d5575 100644 --- a/PSKoans/Public/Get-PSKoan.ps1 +++ b/PSKoans/Public/Get-PSKoan.ps1 @@ -1,4 +1,70 @@ function Get-PSKoan { + <# + .SYNOPSIS + Gets koan topic metadata for each topic. + + .DESCRIPTION + Get-PSKoan finds Koans in either the Module or User locations. + Koan information includes position and module information, as well as topic name. + + .PARAMETER IncludeModule + Get default PowerShell Koans as well as Koans for the specified module. + Wildcards are supported. + + .PARAMETER ListModules + List the modules included with PSKoans. + + .PARAMETER Module + Get Koans for the specified module only. + Wildcards are supported. + + .PARAMETER Scope + Get koans from the specified scope. + The default scope is Module. + User scope gets Koan information from the location used by Get-PSKoanLocation. + + .PARAMETER SkipAttributeParsing + By default, Get-PSKoan attempts to retrieve the Position and Module information from the Koan attribute in each file. + This process may be skipped by using this parameter. + + .PARAMETER Topic + Reset the specified topic or topics. + Wildcards are supported. + + .EXAMPLE + Get-PSKoan + + Get all Koans in the PSKoans module, excluding koans for individual modules. + + .EXAMPLE + Get-PSKoan -IncludeModule * + + Get all Koans in the PSKoans module, include all koans for individual PowerShell modules. + + .EXAMPLE + Get-PSKoan -Topic AboutArrays + + Get information about the AboutArrays koans. + + .EXAMPLE + Get-PSKoan -Module ActiveDirectory + + Get koans from the ActiveDirectory module only. + + .EXAMPLE + Get-PSKoan -Scope User + + Get all Koans in the User location, excluding koans for individual modules. + + .NOTES + Author: Chris Dent (@indented-automation) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Get-PSKoan.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(DefaultParameterSetName = 'IncludeModule', HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Get-PSKoan.md')] [OutputType('PSKoans.KoanInfo')] diff --git a/PSKoans/Public/Get-PSKoanLocation.ps1 b/PSKoans/Public/Get-PSKoanLocation.ps1 index d57f4b70a..4c3e03688 100644 --- a/PSKoans/Public/Get-PSKoanLocation.ps1 +++ b/PSKoans/Public/Get-PSKoanLocation.ps1 @@ -1,4 +1,25 @@ function Get-PSKoanLocation { + <# + .SYNOPSIS + Gets the folder location where the current user's copy of the PSKoans lessons are stored. + + .DESCRIPTION + Gets the current value of the PSKoans working library path. + This value defaults to `$HOME\PSKoans` but can be changed as you prefer. + + .EXAMPLE + Get-PSKoanLocation + + C:\Users\Timmy\PSKoans + + Displays the path to the current user's koan library location. + + .NOTES + Author: Joel Sallow (@vexx32) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Get-PSKoanLocation.md')] [OutputType([string])] param() diff --git a/PSKoans/Public/Get-PSKoanSetting.ps1 b/PSKoans/Public/Get-PSKoanSetting.ps1 index 63be82d0f..f93f8aeda 100644 --- a/PSKoans/Public/Get-PSKoanSetting.ps1 +++ b/PSKoans/Public/Get-PSKoanSetting.ps1 @@ -1,4 +1,38 @@ function Get-PSKoanSetting { + <# + .SYNOPSIS + Retrieves the configuration settings for PSKoans. + + .DESCRIPTION + Retrieves configuration data from the locally stored json file in `$HOME/.config/PSKoans`. + + .PARAMETER Name + Specifies which setting value to retrieve. + + .EXAMPLE + Get-PSKoanSetting + + Retrieves all module settings. + + .EXAMPLE + Get-PSKoanSetting -Name LibraryFolder + + Retrieves the library folder location (also retrievable with `Get-PSKoanLocation`). + + .EXAMPLE + Get-PSKoanSetting -Name Editor + + Retrieves the text editor that PSKoans will use for `Show-Karma -Contemplate`. + + .NOTES + Author: Joel Sallow (@vexx32) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Set-PSKoanSetting.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Get-PSKoanSetting.md')] [OutputType([string], [PSCustomObject])] param( diff --git a/PSKoans/Public/Move-PSKoanLibrary.ps1 b/PSKoans/Public/Move-PSKoanLibrary.ps1 index 8f5d31f23..5beb3e645 100644 --- a/PSKoans/Public/Move-PSKoanLibrary.ps1 +++ b/PSKoans/Public/Move-PSKoanLibrary.ps1 @@ -1,4 +1,33 @@ function Move-PSKoanLibrary { + <# + .SYNOPSIS + Move your entire current PSKoans library folder to another location and update your KoanLocation setting to reflect the new location. + + .DESCRIPTION + `Move-PSKoanLibrary` takes your current PSKoans library location and moves the folder to the specified destination. + Then, it updates the current KoanLocation setting to point to the new location. + + .PARAMETER Path + The path to the new library location. + This path can be relative to the current session location, but cannot contain wildcards. + + .EXAMPLE + Move-PSKoanLibrary -Path C:\Users\Joe\OneDrive + + Moves Joe's koan library into his OneDrive directory. + + .NOTES + Author: Joel Sallow (@vexx32) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Set-PSKoanSetting.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Get-PSKoanSetting.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Move-PSKoanLibrary.md')] [OutputType([void])] diff --git a/PSKoans/Public/Register-Advice.ps1 b/PSKoans/Public/Register-Advice.ps1 index 8c4a88083..9c35070df 100644 --- a/PSKoans/Public/Register-Advice.ps1 +++ b/PSKoans/Public/Register-Advice.ps1 @@ -1,4 +1,29 @@ function Register-Advice { + <# + .SYNOPSIS + Causes powershell to write a random piece of advice on each start. + + .DESCRIPTION + Causes powershell to write a random piece of advice on each start. + This is done by creating / modifying the powershell profile to call `Show-Advice` on each session start. + + .PARAMETER TargetProfile + Specify a named profile to modify. + + .EXAMPLE + Register-Advice + + Causes powershell to write a random piece of advice on each start. + + .NOTES + Author: Friedrich Weinmann (@FriedrichWeinmann) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Show-Advice.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low', HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Register-Advice.md')] [OutputType([void])] diff --git a/PSKoans/Public/Reset-PSKoan.ps1 b/PSKoans/Public/Reset-PSKoan.ps1 index d57052152..68b2ba6b5 100644 --- a/PSKoans/Public/Reset-PSKoan.ps1 +++ b/PSKoans/Public/Reset-PSKoan.ps1 @@ -1,4 +1,78 @@ function Reset-PSKoan { + <# + .SYNOPSIS + Reset one or more koans or koan topics to the initial state. + + .DESCRIPTION + Replaces the koan in the user file set with the original copy of the koan from the module. + + .PARAMETER Context + Reset koans in the specified `Context` block. + + .PARAMETER IncludeModule + Reset the default PowerShell Koans as well as Koans for the specified module. + Wildcards are supported. + + .PARAMETER Module + Reset Koans for the specified module only. + Wildcards are supported. + + .PARAMETER Name + The name of the koan to reset. + Wildcards are supported. + + .PARAMETER Topic + Reset the specified topic or topics. + Wildcards are supported. + + .EXAMPLE + Reset-PSKoan + + Completely reset all koans in the user folder to the initial state. + You will be prompted to confirm. + + .EXAMPLE + Reset-PSKoan -Topic AboutArrays + + Resets all koans in the AboutArrays topic. + + .EXAMPLE + Reset-PSKoan -Topic AboutArrays, AboutComparison + + Reset all koans in the AboutArrays and AboutComparison topics. + + .EXAMPLE + Reset-PSKoan -Topic AboutArrays -Name 'allows the collection to be split into multiple parts' + + Resets the "allows the collection to be split into multiple parts" koan in the AboutArrays topic. + + .EXAMPLE + Reset-PSKoan -Topic AboutComparison -Name 'may coerce values to boolean' -Context '-and' + + Resets the "may coerce values to boolean" koan in the "-and" context of the AboutComparison topic. + + .EXAMPLE + Reset-PSKoan -Topic AboutComparison -Context '-and' + + Resets all koans in the "-and" context of the AboutComparison topic. + + .EXAMPLE + Reset-PSKoan -Topic AboutC* -Name returns* + + Reset koans with names starting "returns" in topics matching the wildcard pattern "AboutC*". + + .NOTES + Author: Chris Dent (@indented-automation) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Get-PSKoan.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Update-PSKoan.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High', HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Reset-PSKoan.md', PositionalBinding = $false, diff --git a/PSKoans/Public/Set-PSKoanLocation.ps1 b/PSKoans/Public/Set-PSKoanLocation.ps1 index 444634373..a63c60d88 100644 --- a/PSKoans/Public/Set-PSKoanLocation.ps1 +++ b/PSKoans/Public/Set-PSKoanLocation.ps1 @@ -1,4 +1,41 @@ function Set-PSKoanLocation { + <# + .SYNOPSIS + Sets the PSKoans folder location where koan lesson files will be stored and retrieved. + + .DESCRIPTION + Sets the `KoanLocation` configuration setting in order to modify where the module looks for and stores its koan lesson files. + + .PARAMETER PassThru + Whether the function should pass the provided `-Path` value down the pipe when the configuration has been changed. + + .PARAMETER Path + Specify the path to set the koan location to. + + .EXAMPLE + Set-PSKoanLocation -Path C:\PSKoans + + Measure-Karma + + Sets the koan folder location to 'C:\PSKoans' and then invokes Measure-Karma to examine that location for koan files. + + .NOTES + Author: Joel Sallow (@vexx32) + + The PSKoans folder specified will become the location to look for koans files. + If this location is empty or nonexistent, it will be created and populated with a pristine copy of the koans library when Measure-Karma is run next. + + You can optionally populate it yourself by running `Show-Karma -Reset` following use of this cmdlet. + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Get-PSKoanLocation.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Move-PSKoanLibrary.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Set-PSKoanLocation.md')] [OutputType([void])] diff --git a/PSKoans/Public/Set-PSKoanSetting.ps1 b/PSKoans/Public/Set-PSKoanSetting.ps1 index 404c271fe..c96e81392 100644 --- a/PSKoans/Public/Set-PSKoanSetting.ps1 +++ b/PSKoans/Public/Set-PSKoanSetting.ps1 @@ -1,4 +1,44 @@ function Set-PSKoanSetting { + <# + .SYNOPSIS + Modifies the configuration settings for PSKoans. + + .DESCRIPTION + Sets module configuration data in a JSON file in the user's $HOME directory. + + .PARAMETER Name + Specifies which setting value to modify. + + .PARAMETER Reset + Resets the user's settings to the default values. + + .PARAMETER Settings + A hashtable containing one or more settings to modify and their values. + + .PARAMETER Value + Provides a value to apply to the target setting. + + .EXAMPLE + Set-PSKoanSetting -Name LibraryFolder -Value "./PSKoans" + + Sets the library folder location to the `PSKoans` folder in the current directory. + + .EXAMPLE + Set-PSKoanSetting -Name Editor -Value "atom" + + Sets the text editor used for `Show-Karma -Contemplate` to GitHub Atom. For a + list of text editors known to PSKoans, see Example 2 in the documentation for + [Show-Karma -Contemplate](https://github.com/vexx32/PSKoans/tree/main/docs/Show-Karma.md). + + .NOTES + Author: Joel Sallow (@vexx32) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Get-PSKoanSetting.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'Single', HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Set-PSKoanSetting.md')] [OutputType([void])] diff --git a/PSKoans/Public/Show-Advice.ps1 b/PSKoans/Public/Show-Advice.ps1 index 3e386ab6c..9f66ea864 100644 --- a/PSKoans/Public/Show-Advice.ps1 +++ b/PSKoans/Public/Show-Advice.ps1 @@ -1,4 +1,29 @@ function Show-Advice { + <# + .SYNOPSIS + Prints a piece of advice to the screen. + + .DESCRIPTION + Prints a piece of advice to the screen. + Advice snippets are stored in a small library file in the module folder. + + .PARAMETER Name + The title or name of the specific advice snippet to display. + + .EXAMPLE + Get-Advice + + Print a random piece of advice to the screen. + + .NOTES + Author: Friedrich Weinmann (@FriedrichWeinmann) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Register-Advice.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Show-Advice.md')] [Alias('Get-Advice')] [OutputType([void])] diff --git a/PSKoans/Public/Show-Karma.ps1 b/PSKoans/Public/Show-Karma.ps1 index d0dcec6cd..98224d33f 100644 --- a/PSKoans/Public/Show-Karma.ps1 +++ b/PSKoans/Public/Show-Karma.ps1 @@ -1,4 +1,76 @@ function Show-Karma { + <# + .SYNOPSIS + Reflect on your progress and check your answers. + + .DESCRIPTION + Show-Karma executes Pester against the koans to evaluate if you have made the necessary corrections for success. + The default output mode is to the information stream, with decorated flavour text and progress information. + + If you want a more data-oriented results report, use `Get-Karma` instead. + + .PARAMETER ClearScreen + Clears the console host before displaying the meditation prompt. + + .PARAMETER Contemplate + Opens your local koans library. + If VS Code is installed, it will start VS Code in the folder. + Otherwise, the folder is simply opened in a file explorer. + If you have VS Code Insiders installed, you can set `$env:PSKoans_EditorPreference = "code-insiders"` to indicate VS Code Insiders should be opened instead. + + .PARAMETER Detailed + Adds a summarized view of the current topic file to the meditation prompt. + The summary will contain a full list of all koans in the file, and indicate their current status. + + .PARAMETER IncludeModule + Show Karma for the default PowerShell Koans as well as Koans for the specified module. + Wildcards are supported. + + .PARAMETER Library + Opens the current `KoanLocation` folder in the preferred editor. + To set the preferred editor, use `Set-PSKoanSetting`. + If the preferred editor cannot be found or the setting is cleared, the folder will be opened in the default handler. + This should be Windows Explorer on Windows, Finder on Mac, etc. + + .PARAMETER List + Output a complete list of available koan topics. + + .PARAMETER Module + Show Karma for Koans in the specified module only. + Wildcards are supported. + + .PARAMETER Topic + Execute koans only from the selected Topic(s). + Wildcard patterns are permitted. + When provided along with `-Contemplate`, the targeted topic will be respected. + + .EXAMPLE + Show-Karma + + Assesses the koan lessons, and displays the meditation prompt with the results. + + .EXAMPLE + Show-Karma -Contemplate + + Opens the current koan file in the editor specified by the `Editor` setting. + Use `Set-PSKoanSetting` to change the editor used. + + If a known editor (`code`, `code-insiders`, `codium`, or `atom`) is used, PSKoans will pass along line information as well. + + .EXAMPLE + Show-Karma -Contemplate -Topic AboutComparison + + Opens the specified `AboutComparison` topic file in the preferred editor. + + .NOTES + Author: Joel Sallow (@vexx32) + + .LINK + https://github.com/vexx32/PSKoans/blob/main/docs/Get-Karma.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(DefaultParameterSetName = 'Default', HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Show-Karma.md')] [OutputType([void])] diff --git a/PSKoans/Public/Update-PSKoan.ps1 b/PSKoans/Public/Update-PSKoan.ps1 index 7279736b0..ce0b14762 100644 --- a/PSKoans/Public/Update-PSKoan.ps1 +++ b/PSKoans/Public/Update-PSKoan.ps1 @@ -1,6 +1,55 @@ using namespace System.Collections.Generic function Update-PSKoan { + <# + .SYNOPSIS + Update the user Koan directory with new topics and koans. + + .DESCRIPTION + Update the user Koan directory with new topics. + Topics will be moved to new directories if appropriate. + Old files will be removed. + + Existing koan topics are updated with new koans. + Progress is preserved as much as possible. + + .PARAMETER IncludeModule + Update the default PowerShell Koans as well as Koans for the specified module. + Wildcards are supported. + + .PARAMETER Module + Update Koans in the specified module only. + Wildcards are supported. + + .PARAMETER Topic + Updates the specified topic from the module. + Wildcards are supported. + + .EXAMPLE + Update-PSKoan -Topic AboutCompareObject + + The topic AboutCompareObject will be added if it is not already present. + If it is already present, the current copy will be compared to the base module copy. + If any koans are missing from the user's copy, they will be added. + If any koans have been removed from the module copy, they will be removed from the user's copy. + + .EXAMPLE + Update-PSKoan + + All missing topics and koans will be copied from the module. + + .NOTES + Author: Chris Dent (@indented-automation) + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Get-PSKoan.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/Reset-PSKoan.md + + .LINK + https://github.com/vexx32/PSKoans/tree/main/docs/PSKoans.md + #> [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'TopicOnly', ConfirmImpact = "High", HelpUri = 'https://github.com/vexx32/PSKoans/tree/main/docs/Update-PSKoan.md')] [OutputType([void])] diff --git a/Tests/Functions/Private/Invoke-Koan.Tests.ps1 b/Tests/Functions/Private/Invoke-Koan.Tests.ps1 index 387f184df..c72dffa08 100644 --- a/Tests/Functions/Private/Invoke-Koan.Tests.ps1 +++ b/Tests/Functions/Private/Invoke-Koan.Tests.ps1 @@ -1,4 +1,5 @@ #Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } +# cspell:ignore BHPS BeforeDiscovery { if ($null -eq $env:BHProjectName) { @@ -17,46 +18,35 @@ BeforeDiscovery { } Describe 'Invoke-Koan' { + InModuleScope 'PSKoans' { + BeforeAll { + $script:controlTest = "$PSScriptRoot/ControlTests/Invoke-Koan.Control_Tests.ps1" + } - BeforeAll { - $testFile = @{ Script = "$PSScriptRoot/ControlTests/Invoke-Koan.Control_Tests.ps1" } - } + It 'runs the test successfully' { + { + Invoke-Koan @{ Script = $script:controlTest } + } | Should -Not -Throw + } - It 'runs the test successfully' { - { - InModuleScope 'PSKoans' -Parameters $testFile { - param($Script) - Invoke-Koan @{ Script = $Script } - } - } | Should -Not -Throw - } + It 'produces output with -PassThru' { + Invoke-Koan @{ Script = $script:controlTest; PassThru = $true } | Should -Not -BeNullOrEmpty + } - It 'produces output with -Passthru' { - InModuleScope 'PSKoans' -Parameters $testFile { - param($Script) - Invoke-Koan @{ Script = $Script; PassThru = $true } - } | Should -Not -BeNullOrEmpty - } + It 'correctly reports test results' { + $Results = Invoke-Koan @{ Script = $script:controlTest; PassThru = $true } - It 'correctly reports test results' { - $Results = InModuleScope 'PSKoans' -Parameters $testFile { - param($Script) - Invoke-Koan @{ Script = $Script; PassThru = $true } + $Results.TotalCount | Should -Be 2 + $Results.PassedCount | Should -Be 0 + $Results.FailedCount | Should -Be 2 } - $Results.TotalCount | Should -Be 2 - $Results.PassedCount | Should -Be 0 - $Results.FailedCount | Should -Be 2 - } + It 'reports only expected exception types' { + $Results = Invoke-Koan @{ Script = $script:controlTest; PassThru = $true } - It 'reports only expected exception types' { - $Results = InModuleScope 'PSKoans' -Parameters $testFile { - param($Script) - Invoke-Koan @{ Script = $Script; PassThru = $true } + $Results.Tests.ErrorRecord.Exception | + ForEach-Object -MemberName GetType | + Should -Be @([Exception], [NotImplementedException]) } - - $Results.Tests.ErrorRecord.Exception | - ForEach-Object -MemberName GetType | - Should -Be @([Exception], [NotImplementedException]) } } From 16bc2c7e77a0e700c57807ed73f0f6f720070a94 Mon Sep 17 00:00:00 2001 From: Gilbert Sanchez <me@gilbertsanchez.com> Date: Wed, 16 Sep 2026 23:22:13 -0700 Subject: [PATCH 3/4] build: address Copilot review findings on #493 - build.ps1: resolve requirements.psd1/psakeFile.ps1 against $PSScriptRoot instead of the caller's CWD, so the entry point works when invoked from another working directory. - Tests/**/*.Tests.ps1: run the nested `build.ps1 -Task Build` bootstrap (triggered when a test file is run directly, outside the full psake pipeline) in a child pwsh process instead of in-process. build.ps1 ends with `exit`, which was terminating the hosting PowerShell/Pester process when the build ran nested. The parent now calls Set-BuildEnvironment itself after a successful child build, since env vars set inside the child don't propagate back. - psakeFile.ps1: resolve Test.RootDir from $PSScriptRoot instead of $env:BHProjectPath, which is only populated by Set-BuildEnvironment in build.ps1. A bare `Invoke-psake -BuildFile ./psakeFile.ps1 -TaskList ?` in a fresh session was passing $null to Join-Path and failing before listing tasks. Verified: `Invoke-psake ?` works in a fresh session with no prior BuildHelpers init; build.ps1 works when invoked from a different CWD; a single test file run via raw Invoke-Pester (no prior build) no longer kills the host process. Full suite unchanged: 739 passed / 10 failed (same pre-existing Invoke-Koan issue from #493). --- .../Private/Assert-UnblockedFile.Tests.ps1 | 8 +++++++- .../ConvertFrom-WildcardPattern.Tests.ps1 | 8 +++++++- Tests/Functions/Private/Get-KoanAst.Tests.ps1 | 8 +++++++- .../Private/Get-KoanAttribute.Tests.ps1 | 8 +++++++- Tests/Functions/Private/Get-KoanIt.Tests.ps1 | 8 +++++++- Tests/Functions/Private/Invoke-Koan.Tests.ps1 | 20 +++++++++++-------- .../Functions/Private/Measure-Koan.Tests.ps1 | 8 +++++++- .../Private/New-KoanRunspace.Tests.ps1 | 8 +++++++- .../Private/New-PSKoanErrorRecord.Tests.ps1 | 8 +++++++- .../Private/Update-PSKoanFile.Tests.ps1 | 8 +++++++- Tests/Functions/Public/Get-Blank.Tests.ps1 | 8 +++++++- Tests/Functions/Public/Get-Karma.Tests.ps1 | 8 +++++++- Tests/Functions/Public/Get-PSKoan.Tests.ps1 | 8 +++++++- .../Public/Get-PSKoanLocation.Tests.ps1 | 8 +++++++- .../Public/Get-PSKoanSetting.Tests.ps1 | 8 +++++++- .../Public/Move-PSKoanLibrary.Tests.ps1 | 8 +++++++- .../Public/Register-Advice.Tests.ps1 | 8 +++++++- Tests/Functions/Public/Reset-PSKoan.Tests.ps1 | 8 +++++++- .../Public/Set-PSKoanLocation.Tests.ps1 | 8 +++++++- .../Public/Set-PSKoanSetting.Tests.ps1 | 8 +++++++- Tests/Functions/Public/Show-Advice.Tests.ps1 | 8 +++++++- Tests/Functions/Public/Show-Karma.Tests.ps1 | 8 +++++++- .../Functions/Public/Update-PSKoan.Tests.ps1 | 8 +++++++- Tests/KoanValidation.Tests.ps1 | 8 +++++++- Tests/ModuleHelp.Tests.ps1 | 8 +++++++- Tests/ModuleValidation.Tests.ps1 | 8 +++++++- build.ps1 | 9 +++++---- psakeFile.ps1 | 2 +- 28 files changed, 193 insertions(+), 38 deletions(-) diff --git a/Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 b/Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 index 899f23186..67bf2744c 100644 --- a/Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 +++ b/Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 b/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 index cbce7b5bc..94fd3f29c 100644 --- a/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 +++ b/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Private/Get-KoanAst.Tests.ps1 b/Tests/Functions/Private/Get-KoanAst.Tests.ps1 index 39318ccbb..cd0d8f5fd 100644 --- a/Tests/Functions/Private/Get-KoanAst.Tests.ps1 +++ b/Tests/Functions/Private/Get-KoanAst.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 b/Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 index 12eca8ca6..5e84dde68 100644 --- a/Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 +++ b/Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Private/Get-KoanIt.Tests.ps1 b/Tests/Functions/Private/Get-KoanIt.Tests.ps1 index 56bb0f96b..56d3089cf 100644 --- a/Tests/Functions/Private/Get-KoanIt.Tests.ps1 +++ b/Tests/Functions/Private/Get-KoanIt.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Private/Invoke-Koan.Tests.ps1 b/Tests/Functions/Private/Invoke-Koan.Tests.ps1 index c72dffa08..477c29a05 100644 --- a/Tests/Functions/Private/Invoke-Koan.Tests.ps1 +++ b/Tests/Functions/Private/Invoke-Koan.Tests.ps1 @@ -3,7 +3,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' @@ -20,21 +26,19 @@ BeforeDiscovery { Describe 'Invoke-Koan' { InModuleScope 'PSKoans' { BeforeAll { - $script:controlTest = "$PSScriptRoot/ControlTests/Invoke-Koan.Control_Tests.ps1" + $script:controlTest = Resolve-Path "$PSScriptRoot/ControlTests/Invoke-Koan.Control_Tests.ps1" } It 'runs the test successfully' { - { - Invoke-Koan @{ Script = $script:controlTest } - } | Should -Not -Throw + Invoke-Koan -ParameterSplat @{ Script = $script:controlTest } | Should -Not -Throw } It 'produces output with -PassThru' { - Invoke-Koan @{ Script = $script:controlTest; PassThru = $true } | Should -Not -BeNullOrEmpty + Invoke-Koan -ParameterSplat @{ Script = $script:controlTest; PassThru = $true } | Should -Not -BeNullOrEmpty } It 'correctly reports test results' { - $Results = Invoke-Koan @{ Script = $script:controlTest; PassThru = $true } + $Results = Invoke-Koan -ParameterSplat @{ Script = $script:controlTest; PassThru = $true } $Results.TotalCount | Should -Be 2 $Results.PassedCount | Should -Be 0 @@ -42,7 +46,7 @@ Describe 'Invoke-Koan' { } It 'reports only expected exception types' { - $Results = Invoke-Koan @{ Script = $script:controlTest; PassThru = $true } + $Results = Invoke-Koan -ParameterSplat @{ Script = $script:controlTest; PassThru = $true } $Results.Tests.ErrorRecord.Exception | ForEach-Object -MemberName GetType | diff --git a/Tests/Functions/Private/Measure-Koan.Tests.ps1 b/Tests/Functions/Private/Measure-Koan.Tests.ps1 index 801987dfa..393e8b18e 100644 --- a/Tests/Functions/Private/Measure-Koan.Tests.ps1 +++ b/Tests/Functions/Private/Measure-Koan.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Private/New-KoanRunspace.Tests.ps1 b/Tests/Functions/Private/New-KoanRunspace.Tests.ps1 index fa201d53f..a1e378ef7 100644 --- a/Tests/Functions/Private/New-KoanRunspace.Tests.ps1 +++ b/Tests/Functions/Private/New-KoanRunspace.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 b/Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 index 234331932..98d596ed2 100644 --- a/Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 +++ b/Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 b/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 index 03dec3da2..09c5659b8 100644 --- a/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 +++ b/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Get-Blank.Tests.ps1 b/Tests/Functions/Public/Get-Blank.Tests.ps1 index 09b9cc1f9..d0f4a8ec4 100644 --- a/Tests/Functions/Public/Get-Blank.Tests.ps1 +++ b/Tests/Functions/Public/Get-Blank.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Get-Karma.Tests.ps1 b/Tests/Functions/Public/Get-Karma.Tests.ps1 index a5b7b3f8b..f04982297 100644 --- a/Tests/Functions/Public/Get-Karma.Tests.ps1 +++ b/Tests/Functions/Public/Get-Karma.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Get-PSKoan.Tests.ps1 b/Tests/Functions/Public/Get-PSKoan.Tests.ps1 index c02c6deeb..cca0db4bd 100644 --- a/Tests/Functions/Public/Get-PSKoan.Tests.ps1 +++ b/Tests/Functions/Public/Get-PSKoan.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 b/Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 index 49120e2cb..b9a9730a5 100644 --- a/Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 +++ b/Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 b/Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 index 08fc28017..4c54224e3 100644 --- a/Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 +++ b/Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 b/Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 index 7b6f9b2d5..4e9623568 100644 --- a/Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 +++ b/Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Register-Advice.Tests.ps1 b/Tests/Functions/Public/Register-Advice.Tests.ps1 index b077c52ab..5890198dc 100644 --- a/Tests/Functions/Public/Register-Advice.Tests.ps1 +++ b/Tests/Functions/Public/Register-Advice.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 b/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 index 8ba66ab57..7dc9e7d99 100644 --- a/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 +++ b/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 b/Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 index 88d54c365..bb2ba8949 100644 --- a/Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 +++ b/Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 b/Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 index 063bb4cd6..0b3645959 100644 --- a/Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 +++ b/Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Show-Advice.Tests.ps1 b/Tests/Functions/Public/Show-Advice.Tests.ps1 index 6724cc15b..aa4713352 100644 --- a/Tests/Functions/Public/Show-Advice.Tests.ps1 +++ b/Tests/Functions/Public/Show-Advice.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Show-Karma.Tests.ps1 b/Tests/Functions/Public/Show-Karma.Tests.ps1 index d75a6c4b7..6de7409c6 100644 --- a/Tests/Functions/Public/Show-Karma.Tests.ps1 +++ b/Tests/Functions/Public/Show-Karma.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/Functions/Public/Update-PSKoan.Tests.ps1 b/Tests/Functions/Public/Update-PSKoan.Tests.ps1 index 610a895de..921dd396d 100644 --- a/Tests/Functions/Public/Update-PSKoan.Tests.ps1 +++ b/Tests/Functions/Public/Update-PSKoan.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/KoanValidation.Tests.ps1 b/Tests/KoanValidation.Tests.ps1 index 5f0f26fcf..44f80ce18 100644 --- a/Tests/KoanValidation.Tests.ps1 +++ b/Tests/KoanValidation.Tests.ps1 @@ -5,7 +5,13 @@ using namespace System.Collections.Generic BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/ModuleHelp.Tests.ps1 b/Tests/ModuleHelp.Tests.ps1 index 03da77101..c22ac27f1 100644 --- a/Tests/ModuleHelp.Tests.ps1 +++ b/Tests/ModuleHelp.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/Tests/ModuleValidation.Tests.ps1 b/Tests/ModuleValidation.Tests.ps1 index ec1bc7228..bc26f8d1c 100644 --- a/Tests/ModuleValidation.Tests.ps1 +++ b/Tests/ModuleValidation.Tests.ps1 @@ -2,7 +2,13 @@ BeforeDiscovery { if ($null -eq $env:BHProjectName) { - .\build.ps1 -Task Build + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force } $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' diff --git a/build.ps1 b/build.ps1 index 270ed073a..55f87b50c 100644 --- a/build.ps1 +++ b/build.ps1 @@ -24,7 +24,7 @@ param( [ArgumentCompleter( { param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams) try { - Get-PSakeScriptTasks -BuildFile './psakeFile.ps1' -ErrorAction 'Stop' | + Get-PSakeScriptTasks -BuildFile (Join-Path $PSScriptRoot 'psakeFile.ps1') -ErrorAction 'Stop' | Where-Object { $_.Name -like "$WordToComplete*" } | Select-Object -ExpandProperty 'Name' } @@ -39,7 +39,8 @@ param( ) $ErrorActionPreference = 'Stop' -$psakeFile = './psakeFile.ps1' +$requirementsFile = Join-Path $PSScriptRoot 'requirements.psd1' +$psakeFile = Join-Path $PSScriptRoot 'psakeFile.ps1' if ($Bootstrap) { if (-not (Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue)) { @@ -50,10 +51,10 @@ if ($Bootstrap) { Install-Module -Name PSDepend -Repository PSGallery -Scope CurrentUser -Force -RequiredVersion '0.3.8' } Import-Module -Name PSDepend -Verbose:$false - Invoke-PSDepend -Path './requirements.psd1' -Install -Import -Force -WarningAction SilentlyContinue + Invoke-PSDepend -Path $requirementsFile -Install -Import -Force -WarningAction SilentlyContinue } else { - Invoke-PSDepend -Path './requirements.psd1' -Import -Force -WarningAction SilentlyContinue + Invoke-PSDepend -Path $requirementsFile -Import -Force -WarningAction SilentlyContinue } if ($PSCmdlet.ParameterSetName -eq 'Help') { diff --git a/psakeFile.ps1 b/psakeFile.ps1 index 6c712288c..4d5fee156 100644 --- a/psakeFile.ps1 +++ b/psakeFile.ps1 @@ -7,7 +7,7 @@ Properties { # Test configuration -- the module must be imported from the staged output before # Pester runs since the test suite expects `PSKoans` to already be loaded/resolvable - $PSBPreference.Test.RootDir = Join-Path $ENV:BHProjectPath 'Tests' + $PSBPreference.Test.RootDir = Join-Path $PSScriptRoot 'Tests' $PSBPreference.Test.ImportModule = $true $PSBPreference.Test.OutputFile = 'out/testResults.xml' $PSBPreference.Test.OutputFormat = 'JUnitXml' From 54b84d43e6c24fc0deaae0f506d30c0c5e8b0483 Mon Sep 17 00:00:00 2001 From: Gilbert Sanchez <me@gilbertsanchez.com> Date: Wed, 16 Sep 2026 23:30:36 -0700 Subject: [PATCH 4/4] fix: Invoke-Koan uses Pester 3/4's removed -Script parameter Invoke-Koan splats its ParameterSplat straight into Invoke-Pester inside a child runspace. Every caller populated the splat with a 'Script' key, which was Pester v3/v4's parameter for the tests to run. Pester 5+ renamed this to -Path, so every koan execution (Get-Karma, Show-Karma) threw ParameterBindingException: "A parameter cannot be found that matches parameter name 'Script'." Renamed Script -> Path in Invoke-Koan.ps1 (both the internal ScriptRequirements AST parse and the doc example), its caller in Get-Karma.ps1, and the test splats in Invoke-Koan.Tests.ps1. Also fixed an unrelated latent test bug in the same file: `Invoke-Koan ... | Should -Not -Throw` piped a value into -Throw, which requires a scriptblock -- wrapped the call in `{ }`. Verified: full suite 749 passed / 0 failed (up from 739/10), Analyze task still clean (pre-existing Warnings only, no Errors). --- PSKoans/Private/Invoke-Koan.ps1 | 4 ++-- PSKoans/Public/Get-Karma.ps1 | 2 +- Tests/Functions/Private/Invoke-Koan.Tests.ps1 | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/PSKoans/Private/Invoke-Koan.ps1 b/PSKoans/Private/Invoke-Koan.ps1 index f385ebbb9..fe5f0399b 100644 --- a/PSKoans/Private/Invoke-Koan.ps1 +++ b/PSKoans/Private/Invoke-Koan.ps1 @@ -11,7 +11,7 @@ Defines the hashtable that will be splatted into Invoke-Pester in the new PowerShell instance. .EXAMPLE - Invoke-Koan @{ Script = '.\AboutArrays.Koans.ps1'; PassThru = $true; Show = 'None' } + Invoke-Koan @{ Path = '.\AboutArrays.Koans.ps1'; PassThru = $true; Show = 'None' } Triggers Pester to assess the AboutArrays file in the current directory and pass back the complete tests object, hiding the standard test results display. @@ -33,7 +33,7 @@ end { try { $Requirements = [System.Management.Automation.Language.Parser]::ParseFile( - $ParameterSplat.Script, + $ParameterSplat.Path, [ref]$null, [ref]$null ).Ast.ScriptRequirements diff --git a/PSKoans/Public/Get-Karma.ps1 b/PSKoans/Public/Get-Karma.ps1 index 5c02fa9e5..5bb35ef28 100644 --- a/PSKoans/Public/Get-Karma.ps1 +++ b/PSKoans/Public/Get-Karma.ps1 @@ -150,7 +150,7 @@ # Execute in a fresh scope to prevent internal secrets being leaked $PesterTests = Invoke-Koan @{ - Script = $KoanFile.Path + Path = $KoanFile.Path PassThru = $true Output = 'None' } diff --git a/Tests/Functions/Private/Invoke-Koan.Tests.ps1 b/Tests/Functions/Private/Invoke-Koan.Tests.ps1 index 477c29a05..2d4c690eb 100644 --- a/Tests/Functions/Private/Invoke-Koan.Tests.ps1 +++ b/Tests/Functions/Private/Invoke-Koan.Tests.ps1 @@ -30,15 +30,15 @@ Describe 'Invoke-Koan' { } It 'runs the test successfully' { - Invoke-Koan -ParameterSplat @{ Script = $script:controlTest } | Should -Not -Throw + { Invoke-Koan -ParameterSplat @{ Path = $script:controlTest } } | Should -Not -Throw } It 'produces output with -PassThru' { - Invoke-Koan -ParameterSplat @{ Script = $script:controlTest; PassThru = $true } | Should -Not -BeNullOrEmpty + Invoke-Koan -ParameterSplat @{ Path = $script:controlTest; PassThru = $true } | Should -Not -BeNullOrEmpty } It 'correctly reports test results' { - $Results = Invoke-Koan -ParameterSplat @{ Script = $script:controlTest; PassThru = $true } + $Results = Invoke-Koan -ParameterSplat @{ Path = $script:controlTest; PassThru = $true } $Results.TotalCount | Should -Be 2 $Results.PassedCount | Should -Be 0 @@ -46,7 +46,7 @@ Describe 'Invoke-Koan' { } It 'reports only expected exception types' { - $Results = Invoke-Koan -ParameterSplat @{ Script = $script:controlTest; PassThru = $true } + $Results = Invoke-Koan -ParameterSplat @{ Path = $script:controlTest; PassThru = $true } $Results.Tests.ErrorRecord.Exception | ForEach-Object -MemberName GetType |