tests/Docs.Examples.Tests.ps1
|
#Requires -Version 7.0 # Every ```powershell block in the user docs parses, and every block not marked # fragment/interactive/network/system runs, as written, in a fresh pwsh with a throwaway # home folder: exit code 0, nothing on stderr, and output matching the ```text # block that follows it. The modes and output rules are documented at the top of # build/DFDocExamples.ps1. Set $Env:DF_DOCS_NETWORK = '1' to run network blocks too. BeforeDiscovery { $repo = Split-Path $PSScriptRoot -Parent . (Join-Path $repo 'build' 'DFDocExamples.ps1') $docs = @( Join-Path $repo 'README.md' Join-Path $repo 'examples' 'README.md' Get-ChildItem (Join-Path $repo 'docs' 'guide') -Filter '*.md' -ErrorAction Ignore | ForEach-Object FullName ) | Where-Object { Test-Path $_ } $script:blocks = foreach ($d in $docs) { foreach ($b in Get-DFDocCodeBlock -Path $d) { @{ Rel = [IO.Path]::GetRelativePath($repo, $b.File) -replace '\\', '/' Line = $b.Line; Code = $b.Code; Mode = $b.Mode Expected = $b.Expected; OutputVaries = $b.OutputVaries } } } $script:runnable = @($script:blocks | Where-Object { $_.Mode -eq 'run' -or ($_.Mode -eq 'network' -and $Env:DF_DOCS_NETWORK -eq '1') }) # examples/*.ps1 are whole profiles. A file with a '# docs-test: parse-only' # line (interactive walkthroughs) is only parsed; the rest also run. $script:profiles = foreach ($f in Get-ChildItem (Join-Path $repo 'examples') -Filter '*.ps1') { $text = Get-Content $f.FullName -Raw @{ Name = $f.Name; Code = $text; ParseOnly = $text -match '(?m)^#\s*docs-test:\s*parse-only' } } } BeforeAll { $repo = Split-Path $PSScriptRoot -Parent . (Join-Path $repo 'build' 'DFDocExamples.ps1') $script:sandbox = Join-Path $TestDrive 'docs-sandbox' $script:modules = New-DFDocModuleCopy -RepoRoot $repo -Destination (Join-Path $TestDrive 'modules') $script:toolVars = Get-DFDocToolVariable -RepoRoot $repo } Describe 'Documentation code blocks parse' { It '<Rel>:<Line> (<Mode>)' -ForEach $script:blocks { $errors = $null $null = [System.Management.Automation.Language.Parser]::ParseInput($Code, [ref]$null, [ref]$errors) $errors | Should -BeNullOrEmpty } } Describe 'Example profiles' { It '<Name> parses' -ForEach $script:profiles { $errors = $null $null = [System.Management.Automation.Language.Parser]::ParseInput($Code, [ref]$null, [ref]$errors) $errors | Should -BeNullOrEmpty } It '<Name> runs as a profile' -ForEach @($script:profiles | Where-Object { -not $_.ParseOnly }) { # Profiles may bootstrap missing tools; force -WhatIf so nothing is installed. $prelude = "`$PSDefaultParameterValues['Install-DFTool:WhatIf'] = `$true`n" $r = Invoke-DFDocExample -Code ($prelude + $Code) -ModulesRoot $script:modules -SandboxRoot $script:sandbox -RemoveVariable $script:toolVars $r.TimedOut | Should -BeFalse $r.StdErr.Trim() | Should -BeNullOrEmpty -Because "stdout was:`n$($r.StdOut)" $r.ExitCode | Should -Be 0 } } Describe 'Documentation code blocks run' { It '<Rel>:<Line>' -ForEach $script:runnable { $r = Invoke-DFDocExample -Code $Code -ModulesRoot $script:modules -SandboxRoot $script:sandbox -RemoveVariable $script:toolVars $r.TimedOut | Should -BeFalse -Because 'the example must finish (is it waiting for input? mark it <!-- interactive -->)' $r.StdErr.Trim() | Should -BeNullOrEmpty -Because "stdout was:`n$($r.StdOut)" $r.ExitCode | Should -Be 0 -Because "stdout was:`n$($r.StdOut)" if ($null -ne $Expected -and -not $OutputVaries) { Compare-DFDocOutput -Expected $Expected -Actual $r.StdOut | Should -BeNullOrEmpty } } } |