Template/tests/QA/module.tests.ps1
$here = Split-Path -Parent $MyInvocation.MyCommand.Path # Convert-path required for PS7 or Join-Path fails $ProjectPath = "$here\..\.." | Convert-Path $ProjectName = (Get-ChildItem $ProjectPath\*\*.psd1 | Where-Object { ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and $(try { Test-ModuleManifest $_.FullName -ErrorAction Stop }catch{$false}) } ).BaseName $SourcePath = (Get-ChildItem $ProjectPath\*\*.psd1 | Where-Object { ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and $(try { Test-ModuleManifest $_.FullName -ErrorAction Stop }catch { $false }) } ).Directory.FullName Describe 'Changelog Management' -Tag 'Changelog' { It 'Changelog has been updated' -skip:( !([bool](Get-Command git -EA SilentlyContinue) -and [bool](&(Get-Process -id $PID).Path -NoProfile -Command 'git rev-parse --is-inside-work-tree 2>$null')) ) { # Get the list of changed files compared with master $HeadCommit = &git rev-parse HEAD $MasterCommit = &git rev-parse origin/master $filesChanged = &git diff $MasterCommit...$HeadCommit --name-only if($HeadCommit -ne $MasterCommit) { # if we're not testing same commit (i.e. master..master) $filesChanged.Where{ (Split-Path $_ -Leaf) -match '^changelog' } | Should -Not -BeNullOrEmpty } } It 'Changelog format compliant with keepachangelog format' -skip:(![bool](Get-Command git -EA SilentlyContinue)) { { Get-ChangelogData (Join-Path $ProjectPath 'CHANGELOG.md') -ErrorAction Stop } | Should -Not -Throw } } Describe 'General module control' -Tags 'FunctionalQuality' { It 'imports without errors' { { Import-Module -Name $ProjectName -Force -ErrorAction Stop } | Should Not Throw Get-Module $ProjectName | Should Not BeNullOrEmpty } It 'Removes without error' { { Remove-Module -Name $ProjectName -ErrorAction Stop } | Should not Throw Get-Module $ProjectName | Should beNullOrEmpty } } #$PrivateFunctions = Get-ChildItem -Path "$ProjectPath\Private\*.ps1" #$PublicFunctions = Get-ChildItem -Path "$ProjectPath\Public\*.ps1" $allModuleFunctions = @() $allModuleFunctions += Get-ChildItem -Path "$SourcePath/Private/*.ps1" $allModuleFunctions += Get-ChildItem -Path "$SourcePath/Public/*.ps1" if (Get-Command Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue) { $scriptAnalyzerRules = Get-ScriptAnalyzerRule } else { if ($ErrorActionPreference -ne 'Stop') { Write-Warning "ScriptAnalyzer not found!" } else { Throw "ScriptAnalyzer not found!" } } foreach ($function in $allModuleFunctions) { Describe "Quality for $($function.BaseName)" -Tags 'TestQuality' { It "$($function.BaseName) has a unit test" { Get-ChildItem "tests\" -recurse -include "$($function.BaseName).tests.ps1" | Should Not BeNullOrEmpty } if ($scriptAnalyzerRules) { It "Script Analyzer for $($function.BaseName)" { forEach ($scriptAnalyzerRule in $scriptAnalyzerRules) { $PSSAResult = (Invoke-ScriptAnalyzer -Path $function.FullName -IncludeRule $scriptAnalyzerRule) ($PSSAResult | Select-Object Message, Line | Out-String) | Should -BeNullOrEmpty } } } } Describe "Help for $($function.BaseName)" -Tags 'helpQuality' { $AbstractSyntaxTree = [System.Management.Automation.Language.Parser]:: ParseInput((Get-Content -raw $function.FullName), [ref]$null, [ref]$null) $AstSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } $ParsedFunction = $AbstractSyntaxTree.FindAll( $AstSearchDelegate, $true ) | ? Name -eq $function.BaseName $FunctionHelp = $ParsedFunction.GetHelpContent() It 'Has a SYNOPSIS' { $FunctionHelp.Synopsis | should not BeNullOrEmpty } It 'Has a Description, with length > 40' { $FunctionHelp.Description.Length | Should beGreaterThan 40 } It 'Has at least 1 example' { $FunctionHelp.Examples.Count | Should beGreaterThan 0 $FunctionHelp.Examples[0] | Should match ([regex]::Escape($function.BaseName)) $FunctionHelp.Examples[0].Length | Should BeGreaterThan ($function.BaseName.Length + 10) } $parameters = $ParsedFunction.Body.ParamBlock.Parameters.name.VariablePath.Foreach{ $_.ToString() } foreach ($parameter in $parameters) { It "Has help for Parameter: $parameter" { $FunctionHelp.Parameters.($parameter.ToUpper()) | Should Not BeNullOrEmpty $FunctionHelp.Parameters.($parameter.ToUpper()).Length | Should BeGreaterThan 25 } } } } |