Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions tests/Build-PSBuildMarkdown.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
Describe 'Build-PSBuildMarkdown' {
BeforeAll {
. "$PSScriptRoot/../PowerShellBuild/Public/Build-PSBuildMarkdown.ps1"
}

BeforeEach {
$script:LocalizedData = @{
NoCommandsExported = 'No commands exported.'
FailedToGenerateMarkdownHelp = 'Failed to generate markdown help: {0}'
}

$script:newMarkdownParams = $null
$script:updateMarkdownParams = @()
}

It 'warns and exits when module exports no commands' {
Mock Import-Module {
[pscustomobject]@{ ExportedCommands = @() }
}
Mock Write-Warning {}
Mock New-MarkdownHelp {}
Mock Remove-Module {}

Build-PSBuildMarkdown \
-ModulePath '/tmp/module' \
-ModuleName 'MyModule' \
-DocsPath '/tmp/docs' \
-Locale 'en-US' \
-Overwrite:$false \
-AlphabeticParamsOrder:$true \
-ExcludeDontShow:$false \
-UseFullTypeName:$false

Should -Invoke Write-Warning -Times 1
Should -Invoke New-MarkdownHelp -Times 0
Should -Invoke Remove-Module -Times 1 -ParameterFilter { $Name -eq 'MyModule' }
}

It 'generates markdown help without force when overwrite is false' {
Mock Import-Module {
[pscustomobject]@{ ExportedCommands = @{ Test = 'Test-Command' } }
}
Mock Test-Path { $false }
Mock New-Item {}
Mock Get-ChildItem { @() }
Mock New-MarkdownHelp {
$script:newMarkdownParams = $PSBoundParameters
}
Mock Remove-Module {}

Build-PSBuildMarkdown \
-ModulePath '/tmp/module' \
-ModuleName 'MyModule' \
-DocsPath '/tmp/docs' \
-Locale 'en-US' \
-Overwrite:$false \
-AlphabeticParamsOrder:$true \
-ExcludeDontShow:$true \
-UseFullTypeName:$false

Should -Invoke New-Item -Times 1 -ParameterFilter { $Path -eq '/tmp/docs' -and $ItemType -eq 'Directory' }
$script:newMarkdownParams.Module | Should -Be 'MyModule'
$script:newMarkdownParams.Locale | Should -Be 'en-US'
$script:newMarkdownParams.OutputFolder | Should -Be ([IO.Path]::Combine('/tmp/docs', 'en-US'))
$script:newMarkdownParams.ErrorAction | Should -Be 'SilentlyContinue'
$script:newMarkdownParams.ContainsKey('Force') | Should -BeFalse
}

It 'updates existing markdown and forces generation when overwrite is true' {
Mock Import-Module {
[pscustomobject]@{ ExportedCommands = @{ Test = 'Test-Command' } }
}
Mock Test-Path { $true }
Mock Get-ChildItem {
@('existing.md')
} -ParameterFilter { $LiteralPath -eq '/tmp/docs' -and $Filter -eq '*.md' -and $Recurse }
Mock Get-ChildItem {
@([pscustomobject]@{ FullName = '/tmp/docs/en-US' })
} -ParameterFilter { $LiteralPath -eq '/tmp/docs' -and $Directory }
Mock Update-MarkdownHelp {
$script:updateMarkdownParams += $PSBoundParameters
}
Mock New-MarkdownHelp {
$script:newMarkdownParams = $PSBoundParameters
}
Mock Remove-Module {}

Build-PSBuildMarkdown \
-ModulePath '/tmp/module' \
-ModuleName 'MyModule' \
-DocsPath '/tmp/docs' \
-Locale 'en-US' \
-Overwrite:$true \
-AlphabeticParamsOrder:$false \
-ExcludeDontShow:$false \
-UseFullTypeName:$true

Should -Invoke Update-MarkdownHelp -Times 1 -ParameterFilter { $Path -eq '/tmp/docs/en-US' }
$script:newMarkdownParams.ContainsKey('Force') | Should -BeTrue
$script:newMarkdownParams.Force | Should -BeTrue
$script:newMarkdownParams.ContainsKey('ErrorAction') | Should -BeFalse
}
}
76 changes: 76 additions & 0 deletions tests/Build-PSBuildModule.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
Describe 'Build-PSBuildModule' {
BeforeAll {
. "$PSScriptRoot/../PowerShellBuild/Public/Build-PSBuildModule.ps1"
}

BeforeEach {
$script:LocalizedData = @{
AddingFileToPsm1 = 'Adding file {0}'
}
}

It 'copies README into culture about-help file when ReadMePath is provided' {
Mock Test-Path {
if ($LiteralPath -eq '/tmp/out') { return $false }
if ($Path -eq '/tmp/out/en-US' -and $PathType -eq 'Container') { return $false }
return $false
}
Mock New-Item {}
Mock Get-ChildItem { @() }
Mock Copy-Item {}
Mock Update-Metadata {}

Build-PSBuildModule \
-Path '/tmp/src' \
-DestinationPath '/tmp/out' \
-ModuleName 'TestModule' \
-ReadMePath '/tmp/src/README.md' \
-Culture 'en-US'

Should -Invoke New-Item -Times 1 -ParameterFilter { $Path -eq '/tmp/out' -and $ItemType -eq 'Directory' }
Should -Invoke New-Item -Times 1 -ParameterFilter { $Path -eq '/tmp/out/en-US' -and $Type -eq 'Directory' -and $Force }
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the ParameterFilter, $Type is used but -Type is an alias for -ItemType on New-Item. Pester parameter filters expose parameters by their canonical name, not aliases. Since the source code at Build-PSBuildModule.ps1:117 calls New-Item $culturePath -Type Directory -Force, PowerShell binds -Type to -ItemType. The filter should use $ItemType -eq 'Directory' instead of $Type -eq 'Directory', otherwise this assertion will not match correctly.

Suggested change
Should -Invoke New-Item -Times 1 -ParameterFilter { $Path -eq '/tmp/out/en-US' -and $Type -eq 'Directory' -and $Force }
Should -Invoke New-Item -Times 1 -ParameterFilter { $Path -eq '/tmp/out/en-US' -and $ItemType -eq 'Directory' -and $Force }

Copilot uses AI. Check for mistakes.
Should -Invoke Copy-Item -Times 1 -ParameterFilter {
$LiteralPath -eq '/tmp/src/README.md' -and
$Destination -eq '/tmp/out/en-US/about_TestModule.help.txt' -and
$Force
}
}

It 'updates manifest FunctionsToExport from Public/*.ps1 basenames' {
Mock Test-Path { $true }
Mock Copy-Item {}
Mock Remove-Item {}
Mock Update-Metadata {}

Mock Get-ChildItem {
@()
} -ParameterFilter { $Path -eq '/tmp/src' -and $Include -contains '*.psm1' }

Mock Get-ChildItem {
@(
[pscustomobject]@{ Name = 'skip.tmp'; FullName = '/tmp/out/skip.tmp' }
)
} -ParameterFilter { $Path -eq '/tmp/out' -and $Recurse }

Mock Get-ChildItem {
@(
[pscustomobject]@{ BaseName = 'Get-Foo' },
[pscustomobject]@{ BaseName = 'Set-Bar' }
)
} -ParameterFilter { $Path -eq '/tmp/src/Public/*.ps1' -and $Recurse }

Build-PSBuildModule \
-Path '/tmp/src' \
-DestinationPath '/tmp/out' \
-ModuleName 'TestModule' \
-Exclude @('\\.tmp$')

Should -Invoke Update-Metadata -Times 1 -ParameterFilter {
$Path -eq '/tmp/out/TestModule.psd1' -and
$PropertyName -eq 'FunctionsToExport' -and
$Value.Count -eq 2 -and
$Value[0] -eq 'Get-Foo' -and
$Value[1] -eq 'Set-Bar'
}
}
}
87 changes: 87 additions & 0 deletions tests/Build-PSBuildUpdatableHelp.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
Describe 'Build-PSBuildUpdatableHelp' {
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR title and description say this adds coverage for Build-PSBuildModule, but the PR also includes new test files for Build-PSBuildUpdatableHelp and Build-PSBuildMarkdown which are not mentioned in the title, description, or the linked issue #98. The description's "Summary" section should be updated to reflect all three test files being added, or the extra test files should be split into separate PRs aligned with their own issues.

Copilot uses AI. Check for mistakes.
BeforeAll {
. "$PSScriptRoot/../PowerShellBuild/Public/Build-PSBuildUpdatableHelp.ps1"
}

BeforeEach {
$script:LocalizedData = @{
MakeCabNotAvailable = 'MakeCab not available on this platform.'
DirectoryAlreadyExists = 'Directory {0} already exists.'
}

$script:ModuleName = 'PSBuildModule'
$script:moduleOutDir = '/tmp/module-out'
$script:newCabCalls = @()
}

It 'warns and exits early when running on non-Windows hosts' {
Mock Write-Warning {}
Mock Get-ChildItem { throw 'should not be called' }
Mock New-Item {}
Mock New-ExternalHelpCab {}

$script:IsWindows = $false

Build-PSBuildUpdatableHelp -DocsPath '/tmp/docs' -OutputPath '/tmp/out'

Should -Invoke Write-Warning -Times 1 -ParameterFilter { $Message -eq 'MakeCab not available on this platform.' }
Should -Invoke Get-ChildItem -Times 0
Should -Invoke New-ExternalHelpCab -Times 0
}

It 'creates output folder and generates one cab per locale on Windows' {
Mock Test-Path { $false }
Mock New-Item {}
Mock Get-ChildItem {
@(
[pscustomobject]@{ Name = 'en-US' },
[pscustomobject]@{ Name = 'fr-FR' }
)
} -ParameterFilter { $Path -eq '/tmp/docs' -and $Directory }
Mock New-ExternalHelpCab {
$script:newCabCalls += $PSBoundParameters
}

$script:IsWindows = $true

Build-PSBuildUpdatableHelp -DocsPath '/tmp/docs' -OutputPath '/tmp/out' -Module 'MyModule'

Should -Invoke New-Item -Times 1 -ParameterFilter { $Path -eq '/tmp/out' -and $ItemType -eq 'Directory' }
$script:newCabCalls.Count | Should -Be 2

$script:newCabCalls[0].CabFilesFolder | Should -Be ([IO.Path]::Combine('/tmp/module-out', 'en-US'))
$script:newCabCalls[0].LandingPagePath | Should -Be ([IO.Path]::Combine('/tmp/docs', 'en-US', 'MyModule.md'))
$script:newCabCalls[0].OutputFolder | Should -Be '/tmp/out'

$script:newCabCalls[1].CabFilesFolder | Should -Be ([IO.Path]::Combine('/tmp/module-out', 'fr-FR'))
$script:newCabCalls[1].LandingPagePath | Should -Be ([IO.Path]::Combine('/tmp/docs', 'fr-FR', 'MyModule.md'))
$script:newCabCalls[1].OutputFolder | Should -Be '/tmp/out'
}

It 'cleans existing output folder before generating cabs on Windows' {
Mock Test-Path { $true }
Mock Get-ChildItem {
@(
[pscustomobject]@{ Name = 'en-US' }
)
} -ParameterFilter { $Path -eq '/tmp/docs' -and $Directory }
Mock Get-ChildItem {
@(
[pscustomobject]@{ FullName = '/tmp/out/existing.cab' }
)
} -ParameterFilter { $Path -eq '/tmp/out' }
Mock Remove-Item {}
Mock New-ExternalHelpCab {
$script:newCabCalls += $PSBoundParameters
}
Mock Write-Verbose {}

$script:IsWindows = $true

Build-PSBuildUpdatableHelp -DocsPath '/tmp/docs' -OutputPath '/tmp/out' -Module 'MyModule'

Should -Invoke Write-Verbose -Times 1
Should -Invoke Remove-Item -Times 1 -ParameterFilter { $Recurse -and $Force }
Should -Invoke New-ExternalHelpCab -Times 1
}
}