Skip to content
Merged
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
206 changes: 206 additions & 0 deletions tests/Build-PSBuildHelp.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# Baseline coverage for the three help-building functions (psake/PowerShellBuild#149).
#
# Build-PSBuildMarkdown, Build-PSBuildMAMLHelp, and Build-PSBuildUpdatableHelp have had no
# tests. The repository does not run its own docs tasks either -- the root psakeFile.ps1 goes
# Init -> Clean -> Build -> Analyze -> Pester -> Publish and never invokes GenerateMarkdown,
# GenerateMAML, or GenerateUpdatableHelp -- so nothing observes these functions today. That
# makes the PlatyPS 1.x migration (#105) a rewrite of three uncovered functions. This file is
# the red-before-green baseline they regress against, written against the CURRENT platyPS
# 0.14.2 behavior.
#
# Every invocation runs in a background job. That is not incidental: platyPS 0.14.2 and
# Microsoft.PowerShell.PlatyPS 1.x each load their own YamlDotNet.dll through NestedModules,
# with different assembly identities, so whichever imports second fails with "Assembly with
# same name is already loaded". A separate runspace does not escape it; only a separate
# process does. Once the migration starts, the old and new implementations can only be
# exercised in the same test run through subprocesses. See Invoke-PSBuildCommandInJob in
# fixtures/FixtureHelpers.psm1.
#
# The fixture is copied into $TestDrive rather than built in place, so nothing under tests/
# is mutated and Pester handles cleanup.

BeforeDiscovery {
# The psake PreConditions on the docs tasks gate on exactly this, so the tests behave the
# same way the shipped tasks do: absent platyPS means skipped, not failed.
$script:platyPSAvailable = [bool](Get-Module -Name 'platyPS' -ListAvailable)

# Build-PSBuildUpdatableHelp returns early on non-Windows, and Windows PowerShell 5.1 has
# no $IsWindows at all, so it takes the Windows path there. Resolved at discovery because
# both branches below are -Skip: conditions.
$script:onWindows = $IsWindows -or $null -eq $IsWindows
}

Describe 'Help building functions' -Skip:(-not $script:platyPSAvailable) {

BeforeAll {
$script:moduleRoot = Split-Path -Path $PSScriptRoot -Parent
$script:builtModulePath = [IO.Path]::Combine($script:moduleRoot, 'Output', 'PowerShellBuild')

Import-Module -Name ([IO.Path]::Combine($PSScriptRoot, 'fixtures', 'FixtureHelpers.psm1')) -Force
}

AfterAll {
Remove-Module -Name 'FixtureHelpers' -Force -ErrorAction SilentlyContinue
}

Context 'Build-PSBuildMarkdown' {

BeforeAll {
$script:markdownScenario = New-PSBuildDocsScenario -Path $TestDrive -Name 'markdown'
$markdownJobParameter = @{
ModulePath = $script:builtModulePath
CommandName = 'Build-PSBuildMarkdown'
Parameter = New-PSBuildMarkdownParameter -Scenario $script:markdownScenario
}
$script:markdownResult = Invoke-PSBuildCommandInJob @markdownJobParameter
}

It 'completes without error' {
$script:markdownResult.ErrorMessage | Should -BeNullOrEmpty
$script:markdownResult.Threw | Should -BeFalse
}

It 'creates the locale directory under the docs path' {
$script:markdownScenario.LocalePath | Should -Exist
}

It 'writes one markdown file per exported command' {
foreach ($commandName in 'Get-Widget', 'Set-Widget') {
Join-Path -Path $script:markdownScenario.LocalePath -ChildPath "$commandName.md" |
Should -Exist
}
}

It 'writes a module landing page named for the module' -Skip {
# Skipped: New-MarkdownHelp is called without -WithModulePage, so the landing page
# is never produced. That is defect 1 of psake/PowerShellBuild#169 and the reason
# Build-PSBuildUpdatableHelp cannot run at all. Unskip when #169 is fixed.

Check warning on line 77 in tests/Build-PSBuildHelp.tests.ps1

View workflow job for this annotation

GitHub Actions / CI / Run Linters

Unknown word (Unskip) Suggestions: (unship, unhip, unrip, unzip, unsaid)
$landingPageName = '{0}.md' -f $script:markdownScenario.ModuleName
Join-Path -Path $script:markdownScenario.LocalePath -ChildPath $landingPageName |
Should -Exist
}

It 'does not document private functions' {
Join-Path -Path $script:markdownScenario.LocalePath -ChildPath 'Test-WidgetName.md' |
Should -Not -Exist
}

It 'produces markdown carrying the 0.14.x schema marker' {
# The 0.14.x front matter carries "external help file" and "schema: 2.0.0". The 1.x
# schema drops the latter, so this assertion is the tripwire that says the
# migration in #150 actually changed the output format.
$markdownPath = Join-Path -Path $script:markdownScenario.LocalePath -ChildPath 'Get-Widget.md'
Get-Content -Path $markdownPath -Raw | Should -Match 'schema:\s*2\.0\.0'
}
}

Context 'Build-PSBuildMAMLHelp' {

BeforeAll {
$script:mamlScenario = New-PSBuildDocsScenario -Path $TestDrive -Name 'maml'
$mamlMarkdownJobParameter = @{
ModulePath = $script:builtModulePath
CommandName = 'Build-PSBuildMarkdown'
Parameter = New-PSBuildMarkdownParameter -Scenario $script:mamlScenario
}
$null = Invoke-PSBuildCommandInJob @mamlMarkdownJobParameter

$mamlJobParameter = @{
ModulePath = $script:builtModulePath
CommandName = 'Build-PSBuildMAMLHelp'
Parameter = @{
Path = $script:mamlScenario.DocsPath
DestinationPath = $script:mamlScenario.OutputPath
}
}
$script:mamlResult = Invoke-PSBuildCommandInJob @mamlJobParameter
}

It 'completes without error' {
$script:mamlResult.ErrorMessage | Should -BeNullOrEmpty
$script:mamlResult.Threw | Should -BeFalse
}

It 'writes the MAML help file into a locale directory under the destination' {
$script:mamlScenario.MamlPath | Should -Exist
}

It 'produces MAML describing the exported commands' {
$maml = Get-Content -Path $script:mamlScenario.MamlPath -Raw
$maml | Should -Match 'Get-Widget'
$maml | Should -Match 'Set-Widget'
}
}

Context 'Build-PSBuildUpdatableHelp' {

BeforeAll {
$script:cabScenario = New-PSBuildDocsScenario -Path $TestDrive -Name 'cab'
$cabMarkdownJobParameter = @{
ModulePath = $script:builtModulePath
CommandName = 'Build-PSBuildMarkdown'
Parameter = New-PSBuildMarkdownParameter -Scenario $script:cabScenario
}
$null = Invoke-PSBuildCommandInJob @cabMarkdownJobParameter

$cabMamlJobParameter = @{
ModulePath = $script:builtModulePath
CommandName = 'Build-PSBuildMAMLHelp'
Parameter = @{
Path = $script:cabScenario.DocsPath
DestinationPath = $script:cabScenario.OutputPath
}
}
$null = Invoke-PSBuildCommandInJob @cabMamlJobParameter

$cabJobParameter = @{
ModulePath = $script:builtModulePath
CommandName = 'Build-PSBuildUpdatableHelp'
Parameter = @{
DocsPath = $script:cabScenario.DocsPath
OutputPath = $script:cabScenario.UpdatableHelpPath
Module = $script:cabScenario.ModuleName
}
}
$script:cabResult = Invoke-PSBuildCommandInJob @cabJobParameter
}

It 'declines to run on platforms without makecab' -Skip:$script:onWindows {

Check warning on line 168 in tests/Build-PSBuildHelp.tests.ps1

View workflow job for this annotation

GitHub Actions / CI / Run Linters

Unknown word (makecab) Suggestions: (marceau, Marceau, make, macao, macau)
$script:cabResult.Threw | Should -BeFalse
$script:cabScenario.UpdatableHelpPath | Should -Not -Exist
}

It 'creates the output directory' -Skip:(-not $script:onWindows) {
# This much works today: the directory is created before the cab step throws.
$script:cabScenario.UpdatableHelpPath | Should -Exist
}

It 'fails parameter binding on the cab step' -Skip:(-not $script:onWindows) {
# Pins the CURRENT broken behavior so the baseline is honest about what happens,
# and so fixing psake/PowerShellBuild#169 forces this test to be revisited rather
# than leaving a silent pass. Delete this test when #169 is fixed; the two below
# replace it.
#
# Either of two independent defects can surface first, depending on the order
# PowerShell binds the splatted parameters: LandingPagePath points at a module page
# that is never generated, and CabFilesFolder is built from the undefined
# $moduleOutDir, which collapses to the bare locale name. Asserting on one of them
# specifically makes this test flaky, so it accepts either.
$script:cabResult.Threw | Should -BeTrue
$script:cabResult.ErrorMessage | Should -Match 'LandingPagePath|CabFilesFolder'
}

It 'produces a cabinet file' -Skip {
# Skipped pending psake/PowerShellBuild#169. This is the acceptance criterion for
# that fix and for the #152 migration, written now so it is not written twice.
Get-ChildItem -Path $script:cabScenario.UpdatableHelpPath -Filter '*.cab' |
Should -Not -BeNullOrEmpty
}

It 'produces the help info manifest' -Skip {
# Skipped pending psake/PowerShellBuild#169. See above.
Get-ChildItem -Path $script:cabScenario.UpdatableHelpPath -Filter '*HelpInfo.xml' |
Should -Not -BeNullOrEmpty
}
}
}
76 changes: 13 additions & 63 deletions tests/Test-PSBuildPester.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# invocation runs in a Start-Job subprocess: two Pester versions cannot coexist in one session,
# and the subprocess lets each test pin the inner Pester version independently of the outer
# framework. The scenarios run against every installed Pester major (5.x and 6.x) to verify the
# shipped function keeps supporting Pester 5 consumers.
# shipped function keeps supporting Pester 5 consumers. The job runner itself lives in
# fixtures/FixtureHelpers.psm1, shared with the other test files that need a fresh session.
#
# The crash fixtures are generated into $TestDrive at runtime, never checked in, so the
# repository's own Pester run can never discover them (see #97 for the convention).
Expand Down Expand Up @@ -34,62 +35,11 @@

Import-Module -Name ([IO.Path]::Combine($PSScriptRoot, 'fixtures', 'FixtureHelpers.psm1')) -Force

# Runs Test-PSBuildPester in a subprocess with a pinned inner Pester version and reports
# what happened. Returns an object with Threw, ErrorMessage, and the Pester version that
# was loaded in the subprocess after the call.
function script:Invoke-TestPSBuildPesterJob {
param(
[string]$InnerPesterVersion,
[string]$Path,
[hashtable]$AdditionalParameters = @{}
)

$job = Start-Job -ScriptBlock {
param($innerPesterVersion, $builtModulePath, $path, $additionalParameters)

Import-Module -Name 'Pester' -RequiredVersion $innerPesterVersion -ErrorAction Stop
Import-Module -Name $builtModulePath -Force -ErrorAction Stop

$testPSBuildPesterParameters = @{
Path = $path
OutputVerbosity = 'None'
ErrorAction = 'Stop'
}
foreach ($key in $additionalParameters.Keys) {
$testPSBuildPesterParameters[$key] = $additionalParameters[$key]
}

$threw = $false
$errorMessage = $null
# Capture the command's output rather than letting it fall through to the job's
# output stream, where the coverage report lines would be interleaved with the
# result object below.
$commandOutput = @()
try {
$commandOutput = @(Test-PSBuildPester @testPSBuildPesterParameters)
} catch {
$threw = $true
$errorMessage = $_.Exception.Message
}

[PSCustomObject]@{
Threw = $threw
ErrorMessage = $errorMessage
Output = $commandOutput
LoadedPesterVersions = @((Get-Module -Name 'Pester').Version.ToString())
}
} -ArgumentList $InnerPesterVersion, $script:builtModulePath, $Path, $AdditionalParameters

$jobResult = $job | Wait-Job | Receive-Job
Remove-Job -Job $job -Force
$jobResult
}

# Scenario directories, generated at runtime.
$script:healthyPath = Join-Path -Path $TestDrive -ChildPath 'healthy'
$script:failingTestPath = Join-Path -Path $TestDrive -ChildPath 'failingtest'

Check warning on line 40 in tests/Test-PSBuildPester.tests.ps1

View workflow job for this annotation

GitHub Actions / CI / Run Linters

Unknown word (failingtest) Suggestions: (failings, faintest, failing's)
$script:beforeAllCrashPath = Join-Path -Path $TestDrive -ChildPath 'beforeallcrash'

Check warning on line 41 in tests/Test-PSBuildPester.tests.ps1

View workflow job for this annotation

GitHub Actions / CI / Run Linters

Unknown word (beforeallcrash)
$script:discoveryCrashPath = Join-Path -Path $TestDrive -ChildPath 'discoverycrash'

Check warning on line 42 in tests/Test-PSBuildPester.tests.ps1

View workflow job for this annotation

GitHub Actions / CI / Run Linters

Unknown word (discoverycrash)
$script:coveragePath = Join-Path -Path $TestDrive -ChildPath 'coverage'
$script:outputPath = Join-Path -Path $TestDrive -ChildPath 'out'
foreach ($directory in @(
Expand Down Expand Up @@ -169,30 +119,30 @@
}

It 'succeeds for a healthy suite' {
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:healthyPath
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:innerVersion -Path $script:healthyPath

$result.Threw | Should -BeFalse
}

It 'fails the build when a test fails' {
# Regression: #52
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:failingTestPath
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:innerVersion -Path $script:failingTestPath

$result.Threw | Should -BeTrue
$result.ErrorMessage | Should -Match 'Pester tests failed'
}

It 'fails the build when a setup block throws' {
# Regression: #128 / #133 (FailedCount alone misses failed blocks)
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:beforeAllCrashPath
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:innerVersion -Path $script:beforeAllCrashPath

$result.Threw | Should -BeTrue
$result.ErrorMessage | Should -Match 'Pester tests failed'
}

It 'fails the build when a test file errors during discovery' {
# Regression: #128 / #133 (FailedCount alone misses failed containers)
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:discoveryCrashPath
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:innerVersion -Path $script:discoveryCrashPath

$result.Threw | Should -BeTrue
$result.ErrorMessage | Should -Match 'Pester tests failed'
Expand All @@ -203,7 +153,7 @@
$additionalParameters = @{
OutputPath = $testResultsPath
}
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:healthyPath -AdditionalParameters $additionalParameters
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:innerVersion -Path $script:healthyPath -AdditionalParameter $additionalParameters

$result.Threw | Should -BeFalse
$testResultsPath | Should -Exist
Expand All @@ -218,7 +168,7 @@
CodeCoverageOutputFile = $coverageOutputPath
CodeCoverageOutputFileFormat = 'JaCoCo'
}
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:coveragePath -AdditionalParameters $additionalParameters
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:innerVersion -Path $script:coveragePath -AdditionalParameter $additionalParameters

$result.Threw | Should -BeFalse
$coverageOutputPath | Should -Exist
Expand All @@ -239,7 +189,7 @@
CodeCoverageOutputFile = $coverageOutputPath
CodeCoverageThreshold = 0.01
}
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:coveragePath -AdditionalParameters $additionalParameters
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:innerVersion -Path $script:coveragePath -AdditionalParameter $additionalParameters

$result.Threw | Should -BeFalse
}
Expand All @@ -253,7 +203,7 @@
CodeCoverageOutputFile = $coverageOutputPath
CodeCoverageThreshold = 0.99
}
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:innerVersion -Path $script:coveragePath -AdditionalParameters $additionalParameters
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:innerVersion -Path $script:coveragePath -AdditionalParameter $additionalParameters

$result.Threw | Should -BeTrue
$result.ErrorMessage | Should -Match 'less than the threshold'
Expand All @@ -275,7 +225,7 @@
# Regression: the finally block called Remove-Module with an empty -Name, which
# raised a parameter-binding error that -ErrorAction SilentlyContinue cannot
# suppress.
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:newestInnerVersion -Path $script:healthyPath
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:newestInnerVersion -Path $script:healthyPath

$result.Threw | Should -BeFalse
$result.ErrorMessage | Should -BeNullOrEmpty
Expand All @@ -285,10 +235,10 @@
# Regression: an unconditional Import-Module Pester -MinimumVersion 5.0.0 loaded the
# newest installed Pester on top of an already-loaded older one, which crashes with a
# Pester.dll version conflict when 5.x and 6.x are installed side by side.
$result = Invoke-TestPSBuildPesterJob -InnerPesterVersion $script:oldestInnerVersion -Path $script:healthyPath
$result = Invoke-TestPSBuildPesterInJob -ModulePath $script:builtModulePath -InnerPesterVersion $script:oldestInnerVersion -Path $script:healthyPath

$result.Threw | Should -BeFalse
$result.LoadedPesterVersions | Should -Be @($script:oldestInnerVersion)
$result.LoadedModuleVersion['Pester'] | Should -Be @($script:oldestInnerVersion)
}
}
}
Loading
Loading